Frank Vannieuwkerke / cc3000_hostdriver_mbedsocket

Fork of cc3000_hostdriver_mbedsocket by Martin Kojtal

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers cc3000_spi.cpp Source File

cc3000_spi.cpp

00001 /*****************************************************************************
00002 *
00003 *  C++ interface/implementation created by Martin Kojtal (0xc0170). Thanks to
00004 *  Jim Carver and Frank Vannieuwkerke for their inital cc3000 mbed port and
00005 *  provided help.
00006 *
00007 *  This version of "host driver" uses CC3000 Host Driver Implementation. Thus
00008 *  read the following copyright:
00009 *
00010 *  Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
00011 *
00012 *  Redistribution and use in source and binary forms, with or without
00013 *  modification, are permitted provided that the following conditions
00014 *  are met:
00015 *
00016 *    Redistributions of source code must retain the above copyright
00017 *    notice, this list of conditions and the following disclaimer.
00018 *
00019 *    Redistributions in binary form must reproduce the above copyright
00020 *    notice, this list of conditions and the following disclaimer in the
00021 *    documentation and/or other materials provided with the
00022 *    distribution.
00023 *
00024 *    Neither the name of Texas Instruments Incorporated nor the names of
00025 *    its contributors may be used to endorse or promote products derived
00026 *    from this software without specific prior written permission.
00027 *
00028 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00029 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00030 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00031 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00032 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00033 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00034 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00035 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00036 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00037 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00038 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00039 *
00040 *****************************************************************************/
00041 #include "cc3000.h"
00042 #include "cc3000_spi.h"
00043 
00044 namespace mbed_cc3000 {
00045 
00046 cc3000_spi::cc3000_spi(PinName cc3000_irq, PinName cc3000_en, PinName cc3000_cs, SPI cc3000_spi, cc3000_event &event, cc3000_simple_link &simple_link, uint32_t max_tx, uint32_t max_rx)
00047   : _wlan_irq(cc3000_irq), _wlan_en(cc3000_en), _wlan_cs(cc3000_cs), _wlan_spi(cc3000_spi), _event(event), _simple_link(simple_link), _max_tx(max_tx), _max_rx(max_rx) {
00048 
00049     _wlan_spi.format(8,1);
00050     _wlan_spi.frequency(12000000);
00051     _wlan_irq.fall(this, &cc3000_spi::WLAN_IRQHandler);
00052 
00053     _wlan_en = 0;
00054     _wlan_cs = 1;
00055     wait_ms(50); /* mbed board delay */
00056 }
00057 
00058 cc3000_spi::~cc3000_spi() {
00059 
00060 }
00061 
00062 void cc3000_spi::wlan_irq_enable()
00063 {
00064     _process_irq = true;
00065     //_wlan_irq.enable_irq();
00066 
00067     if (wlan_irq_read() == 0) {
00068         WLAN_IRQHandler();
00069     }
00070 }
00071 
00072 void cc3000_spi::wlan_irq_disable() {
00073     _process_irq = false;
00074     //_wlan_irq.disable_irq();
00075 }
00076 
00077 uint32_t cc3000_spi::wlan_irq_read() {
00078     return _wlan_irq.read();
00079 }
00080 
00081 void cc3000_spi::close() {
00082     wlan_irq_disable();
00083 }
00084 
00085 void cc3000_spi::open() {
00086    _spi_info.spi_state = eSPI_STATE_POWERUP;
00087    _spi_info.tx_packet_length = 0;
00088    _spi_info.rx_packet_length = 0;
00089     wlan_irq_enable();
00090 }
00091 
00092 uint32_t cc3000_spi::first_write(uint8_t *buffer, uint16_t length) {
00093     _wlan_cs = 0;
00094     wait_us(50);
00095 
00096     /* first 4 bytes of the data */
00097     write_synchronous(buffer, 4);
00098     wait_us(50);
00099     write_synchronous(buffer + 4, length - 4);
00100     _spi_info.spi_state = eSPI_STATE_IDLE;
00101     _wlan_cs = 1;
00102 
00103     return 0;
00104 }
00105 
00106 
00107 uint32_t cc3000_spi::write(uint8_t *buffer, uint16_t length) {
00108     uint8_t pad = 0;
00109     // check the total length of the packet in order to figure out if padding is necessary
00110     if(!(length & 0x0001)) {
00111       pad++;
00112     }
00113     buffer[0] = WRITE;
00114     buffer[1] = HI(length + pad);
00115     buffer[2] = LO(length + pad);
00116     buffer[3] = 0;
00117     buffer[4] = 0;
00118 
00119     length += (SPI_HEADER_SIZE + pad);
00120 
00121     // The magic number resides at the end of the TX/RX buffer (1 byte after the allocated size)
00122     // If the magic number is overwitten - buffer overrun occurred - we will be stuck here forever!
00123     uint8_t *transmit_buffer = _simple_link.get_transmit_buffer();
00124     if (transmit_buffer[_max_tx - 1] != CC3000_BUFFER_MAGIC_NUMBER) {
00125         DBG_CC("System halted - TX buffer overflow detected (buffer size: %d).", _max_tx);
00126         while (1);
00127     }
00128 
00129     if (_spi_info.spi_state == eSPI_STATE_POWERUP) {
00130         while (_spi_info.spi_state != eSPI_STATE_INITIALIZED);
00131     }
00132 
00133     if (_spi_info.spi_state == eSPI_STATE_INITIALIZED) {
00134         // TX/RX transaction over SPI after powerup: IRQ is low - send read buffer size command
00135         first_write(buffer, length);
00136     } else {
00137         // Prevent occurence of a race condition when 2 back to back packets are sent to the
00138         // device, so the state will move to IDLE and once again to not IDLE due to IRQ
00139         wlan_irq_disable();
00140 
00141         while (_spi_info.spi_state != eSPI_STATE_IDLE);
00142 
00143         _spi_info.spi_state = eSPI_STATE_WRITE_IRQ;
00144         //_spi_info.pTxPacket = buffer;
00145         _spi_info.tx_packet_length = length;
00146 
00147         // Assert the CS line and wait until the IRQ line is active, then initialize the write operation
00148         _wlan_cs = 0;
00149 
00150         wlan_irq_enable();
00151     }
00152 
00153     // Wait until the transaction ends
00154     while (_spi_info.spi_state != eSPI_STATE_IDLE);
00155 
00156     return 0;
00157 }
00158 
00159 void cc3000_spi::write_synchronous(uint8_t *data, uint16_t size) {
00160     while(size) {
00161         _wlan_spi.write(*data++);
00162         size--;
00163     }
00164 }
00165 
00166 void cc3000_spi::read_synchronous(uint8_t *data, uint16_t size) {
00167     for (uint32_t i = 0; i < size; i++) {
00168         data[i] = _wlan_spi.write(0x03);
00169     }
00170 }
00171 
00172 uint32_t cc3000_spi::read_data_cont() {
00173    int32_t data_to_recv;
00174    uint8_t *evnt_buff, type;
00175 
00176    //determine the packet type
00177    evnt_buff = _simple_link.get_received_buffer();
00178    data_to_recv = 0;
00179    STREAM_TO_UINT8((uint8_t *)(evnt_buff + SPI_HEADER_SIZE), HCI_PACKET_TYPE_OFFSET, type);
00180 
00181     switch(type) {
00182         case HCI_TYPE_DATA:
00183             // Read the remaining data..
00184             STREAM_TO_UINT16((uint8_t *)(evnt_buff + SPI_HEADER_SIZE), HCI_DATA_LENGTH_OFFSET, data_to_recv);
00185             if (!((HEADERS_SIZE_EVNT + data_to_recv) & 1)) {
00186                data_to_recv++;
00187             }
00188 
00189             if (data_to_recv) {
00190                read_synchronous(evnt_buff + 10, data_to_recv);
00191             }
00192             break;
00193         case HCI_TYPE_EVNT:
00194             // Calculate the rest length of the data
00195             STREAM_TO_UINT8((char *)(evnt_buff + SPI_HEADER_SIZE), HCI_EVENT_LENGTH_OFFSET, data_to_recv);
00196             data_to_recv -= 1;
00197             // Add padding byte if needed
00198             if ((HEADERS_SIZE_EVNT + data_to_recv) & 1) {
00199                  data_to_recv++;
00200             }
00201 
00202             if (data_to_recv) {
00203                read_synchronous(evnt_buff + 10, data_to_recv);
00204             }
00205 
00206             _spi_info.spi_state = eSPI_STATE_READ_EOT;
00207             break;
00208     }
00209     return 0;
00210 }
00211 
00212 void cc3000_spi::set_wlan_en(uint8_t value) {
00213     if (value) {
00214         _wlan_en = 1;
00215     } else {
00216         _wlan_en = 0;
00217     }
00218 }
00219 
00220 void cc3000_spi::WLAN_IRQHandler() {
00221     if (_process_irq) {
00222         if (_spi_info.spi_state == eSPI_STATE_POWERUP) {
00223             // Inform HCI Layer that IRQ occured after powerup
00224             _spi_info.spi_state = eSPI_STATE_INITIALIZED;
00225         } else if (_spi_info.spi_state == eSPI_STATE_IDLE) {
00226             _spi_info.spi_state = eSPI_STATE_READ_IRQ;
00227             /* IRQ line goes low - acknowledge it */
00228              _wlan_cs = 0;
00229             read_synchronous(_simple_link.get_received_buffer(), 10);
00230             _spi_info.spi_state = eSPI_STATE_READ_EOT;
00231 
00232             // The header was read - continue with the payload read
00233             if (!read_data_cont()) {
00234                 // All the data was read - finalize handling by switching to the task
00235                 // Trigger Rx processing
00236                 wlan_irq_disable();
00237                 _wlan_cs = 1;
00238                 // The magic number resides at the end of the TX/RX buffer (1 byte after the allocated size)
00239                 // If the magic number is overwitten - buffer overrun occurred - we will be stuck here forever!
00240                 uint8_t *received_buffer = _simple_link.get_received_buffer();
00241                 if (received_buffer[_max_rx - 1] != CC3000_BUFFER_MAGIC_NUMBER) {
00242                     DBG_CC("System halted - RX buffer overflow detected (buffer size: %d).", _max_rx);
00243                     while (1);
00244                 }
00245 
00246                 _spi_info.spi_state = eSPI_STATE_IDLE;
00247                 _event.received_handler(received_buffer + SPI_HEADER_SIZE);
00248             }
00249         } else if (_spi_info.spi_state == eSPI_STATE_WRITE_IRQ) {
00250             write_synchronous(_simple_link.get_transmit_buffer(), _spi_info.tx_packet_length);
00251             _spi_info.spi_state = eSPI_STATE_IDLE;
00252             _wlan_cs = 1;
00253         }
00254     }
00255 }
00256 
00257 } // namespace mbed_cc3000