Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

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 {
00136         return -1;
00137     }
00138 }
00139 
00140 int BufferedSpi::putc(int c)
00141 {
00142     _txbuf = (char)c;
00143 
00144     return c;
00145 }
00146 
00147 void BufferedSpi::flush_txbuf(void)
00148 {
00149     _txbuf.clear();
00150 }
00151 
00152 int BufferedSpi::puts(const char *s)
00153 {
00154     if (s != NULL) {
00155         const char *ptr = s;
00156 
00157         while (*(ptr) != 0) {
00158             _txbuf = *(ptr++);
00159         }
00160         _txbuf = '\n';  // done per puts definition
00161         BufferedSpi::txIrq();                // only write to hardware in one place
00162         return (ptr - s) + 1;
00163     }
00164     return 0;
00165 }
00166 
00167 extern "C" size_t BufferedSpiThunk(void *buf_spi, const void *s, size_t length)
00168 {
00169     BufferedSpi *buffered_spi = (BufferedSpi *)buf_spi;
00170     return buffered_spi->buffwrite(s, length);
00171 }
00172 
00173 int BufferedSpi::printf(const char *format, ...)
00174 {
00175     va_list arg;
00176     va_start(arg, format);
00177     int r = BufferedPrintfC((void *)this, this->_buf_size, format, arg);
00178     va_end(arg);
00179     return r;
00180 }
00181 
00182 ssize_t BufferedSpi::buffwrite(const void *s, size_t length)
00183 {
00184     /* flush buffer from previous message */
00185     this->flush_txbuf();
00186 
00187     if (wait_cmddata_rdy_high() < 0) {
00188         debug_if(local_debug, "BufferedSpi::buffwrite timeout (%d)\r\n", _timeout);
00189         return -1;
00190     }
00191 
00192     this->enable_nss();
00193 
00194     if (s != NULL && length > 0) {
00195         /* 1st fill _txbuf */
00196         const char *ptr = (const char *)s;
00197         const char *end = ptr + length;
00198 
00199         while (ptr != end) {
00200             _txbuf = *(ptr++);
00201         }
00202         if (length & 1) { /* padding to send the last char */
00203             _txbuf = '\n';
00204             length++;
00205         }
00206 
00207         /* 2nd write in SPI */
00208         BufferedSpi::txIrq();                // only write to hardware in one place
00209 
00210         this->disable_nss();
00211         return ptr - (const char *)s;
00212     }
00213     this->disable_nss();
00214 
00215     return 0;
00216 }
00217 
00218 ssize_t BufferedSpi::buffsend(size_t length)
00219 {
00220     /* wait for dataready = 1 */
00221     if (wait_cmddata_rdy_high() < 0) {
00222         debug_if(local_debug, "BufferedSpi::buffsend timeout (%d)\r\n", _timeout);
00223         return -1;
00224     }
00225 
00226     this->enable_nss();
00227 
00228     /* _txbuffer is already filled with data to send */
00229     /* check if _txbuffer needs padding to send the last char */
00230     if (length & 1) {
00231         _txbuf = '\n';
00232         length++;
00233     }
00234     BufferedSpi::txIrq();                // only write to hardware in one place
00235 
00236     this->disable_nss();
00237 
00238     return length;
00239 }
00240 
00241 ssize_t BufferedSpi::read()
00242 {
00243     return this->read(0);
00244 }
00245 
00246 ssize_t BufferedSpi::read(uint32_t max)
00247 {
00248     uint32_t len = 0;
00249     uint8_t FirstRemoved = 1;
00250     int tmp;
00251 
00252     disable_nss();
00253 
00254     /* wait for data ready is up */
00255     if (wait_cmddata_rdy_rising_event() != 0) {
00256         debug_if(local_debug, "BufferedSpi::read timeout (%d)\r\n", _timeout);
00257         return -1;
00258     }
00259 
00260     enable_nss();
00261     while (dataready.read() == 1 && (len < (_buf_size - 2))) {
00262         tmp = SPI::write(0xAA);  // dummy write to receive 2 bytes
00263 
00264         if (!((len == 0) && (tmp == 0x0A0D) && (FirstRemoved))) {
00265             /* do not take into account the 2 firts \r \n char in the buffer */
00266             if ((max == 0) || (len < max)) {
00267                 _rxbuf = (char)(tmp & 0x00FF);
00268                 _rxbuf = (char)((tmp >> 8) & 0xFF);
00269                 len += 2;
00270             }
00271         } else {
00272             FirstRemoved = 0;
00273         }
00274     }
00275     disable_nss();
00276 
00277     if (len >= _buf_size) {
00278         debug_if(local_debug, "firmware ERROR ES_WIFI_ERROR_STUFFING_FOREVER\r\n");
00279         return -1;
00280     }
00281 
00282     debug_if(local_debug, "SPI READ %d BYTES\r\n", len);
00283 
00284     return len;
00285 }
00286 
00287 void BufferedSpi::txIrq(void)
00288 {
00289     /* write everything available in the _txbuffer */
00290     int value = 0;
00291     int dbg_cnt = 0;
00292     while (_txbuf.available() && (_txbuf.getNbAvailable() > 0)) {
00293         value = _txbuf.get();
00294         if (_txbuf.available() && ((_txbuf.getNbAvailable() % 2) != 0)) {
00295             value |= ((_txbuf.get() << 8) & 0XFF00);
00296             SPI::write(value);
00297             dbg_cnt++;
00298         }
00299     }
00300     debug_if(local_debug, "SPI Sent %d BYTES\r\n", 2 * dbg_cnt);
00301     // disable the TX interrupt when there is nothing left to send
00302     BufferedSpi::attach(NULL, BufferedSpi::TxIrq);
00303     // trigger callback if necessary
00304     if (_cbs[TxIrq]) {
00305         _cbs[TxIrq]();
00306     }
00307     return;
00308 }
00309 
00310 void BufferedSpi::prime(void)
00311 {
00312     BufferedSpi::txIrq();                // only write to hardware in one place
00313     return;
00314 }
00315 
00316 void BufferedSpi::attach(Callback<void()> func, IrqType type)
00317 {
00318     _cbs[type] = func;
00319 }
00320 
00321 void BufferedSpi::sigio(Callback<void()> func)
00322 {
00323     core_util_critical_section_enter();
00324     _sigio_cb = func;
00325     if (_sigio_cb) {
00326         if (_sigio_event == 1) {
00327             _sigio_cb();
00328             _sigio_event = 0;
00329         }
00330     }
00331     core_util_critical_section_exit();
00332 }
00333