Added mutex for multiple SPI devices on the same SPI bus
Fork of cc3000_hostdriver_mbedsocket by
Diff: cc3000_spi.cpp
- Revision:
- 20:30b6ed7bf8fd
- Parent:
- 0:615c697c33b0
- Child:
- 33:9e23b24fb4f3
diff -r 9fdf8b4e41bf -r 30b6ed7bf8fd cc3000_spi.cpp --- a/cc3000_spi.cpp Thu Oct 03 09:49:03 2013 +0200 +++ b/cc3000_spi.cpp Thu Oct 03 17:15:45 2013 +0200 @@ -1,302 +1,302 @@ -/***************************************************************************** -* -* C++ interface/implementation created by Martin Kojtal (0xc0170). Thanks to -* Jim Carver and Frank Vannieuwkerke for their inital cc3000 mbed port and -* provided help. -* -* This version of "host driver" uses CC3000 Host Driver Implementation. Thus -* read the following copyright: -* -* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -*****************************************************************************/ -#include "cc3000.h" -#include "cc3000_spi.h" - -namespace mbed_cc3000 { - -cc3000_spi::cc3000_spi(PinName cc3000_irq, PinName cc3000_en, PinName cc3000_cs, SPI cc3000_spi, IRQn_Type irq_port, cc3000_event &event, cc3000_simple_link &simple_link) - : _wlan_irq(cc3000_irq), _wlan_en(cc3000_en), _wlan_cs(cc3000_cs), _wlan_spi(cc3000_spi), _irq_port(irq_port), - _event(event), _simple_link(simple_link) { - /* TODO = clear pending interrupts for PORTS. This is dependent on the used chip */ - - _wlan_spi.format(8,1); - _wlan_spi.frequency(12000000); - _function_pointer = _wlan_irq.fall(this, &cc3000_spi::WLAN_IRQHandler); - - _wlan_en = 0; - _wlan_cs = 1; -} - -cc3000_spi::~cc3000_spi() { - -} - -void cc3000_spi::wlan_irq_enable() -{ - NVIC_EnableIRQ(_irq_port); -} - -void cc3000_spi::wlan_irq_disable() { - NVIC_DisableIRQ(_irq_port); -} - -void cc3000_spi::wlan_irq_set(uint8_t value) { - if (value) - { - _wlan_en = 1; - } - else - { - _wlan_en = 0; - } -} - -uint32_t cc3000_spi::wlan_irq_read() { - return _wlan_irq.read(); -} - -void cc3000_spi::close() { - if (_simple_link.get_received_buffer() != 0) - { - _simple_link.set_received_buffer(0); - } - wlan_irq_disable(); -} - -// void cc3000_spi::SpiReceiveHandler() { -// _simple_link.usEventOrDataReceived = 1; -// //_simple_link.pucReceivedData = (unsigned char *)pvBuffer; - -// hci_unsolicited_event_handler(); -// } - - -/* TODO - pRxPacket, pTxPacket do we need to hold this pointer ? - SPIRxHandler - remove? -*/ -void cc3000_spi::open() { - _spi_info.spi_state = eSPI_STATE_POWERUP; - //_spi_info.SPIRxHandler = pfRxHandler; - _spi_info.tx_packet_length = 0; - _spi_info.rx_packet_length = 0; - //_rx_buffer[CC3000_RX_BUFFER_SIZE - 1] = CC3000_BUFFER_MAGIC_NUMBER; - //_tx_buffer[CC3000_TX_BUFFER_SIZE - 1] = CC3000_BUFFER_MAGIC_NUMBER; - wlan_irq_enable(); -} - -uint32_t cc3000_spi::first_write(uint8_t *buffer, uint16_t length) { - _wlan_cs = 0; - wait_us(50); - - /* first 4 bytes of the data */ - write_synchronous(buffer, 4); - wait_us(50); - write_synchronous(buffer + 4, length - 4); - _spi_info.spi_state = eSPI_STATE_IDLE; - _wlan_cs = 1; - - return 0; -} - - -uint32_t cc3000_spi::write(uint8_t *buffer, uint16_t length) { - uint8_t pad = 0; - // check the total length of the packet in order to figure out if padding is necessary - if(!(length & 0x0001)) - { - pad++; - } - buffer[0] = WRITE; - buffer[1] = HI(length + pad); - buffer[2] = LO(length + pad); - buffer[3] = 0; - buffer[4] = 0; - - length += (SPI_HEADER_SIZE + pad); - - // The magic number resides at the end of the TX/RX buffer (1 byte after the allocated size) - // If the magic number is overwitten - buffer overrun occurred - we will be stuck here forever! - uint8_t * transmit_buffer = _simple_link.get_transmit_buffer(); - if (transmit_buffer[CC3000_TX_BUFFER_SIZE - 1] != CC3000_BUFFER_MAGIC_NUMBER) - { - while (1); - } - - if (_spi_info.spi_state == eSPI_STATE_POWERUP) - { - while (_spi_info.spi_state != eSPI_STATE_INITIALIZED); - } - - if (_spi_info.spi_state == eSPI_STATE_INITIALIZED) - { - // TX/RX transaction over SPI after powerup: IRQ is low - send read buffer size command - first_write(buffer, length); - } - else - { - // Prevent occurence of a race condition when 2 back to back packets are sent to the - // device, so the state will move to IDLE and once again to not IDLE due to IRQ - wlan_irq_disable(); - - while (_spi_info.spi_state != eSPI_STATE_IDLE); - - _spi_info.spi_state = eSPI_STATE_WRITE_IRQ; - //_spi_info.pTxPacket = buffer; - _spi_info.tx_packet_length = length; - - // Assert the CS line and wait until the IRQ line is active, then initialize the write operation - _wlan_cs = 0; - - wlan_irq_enable(); - } - - // Wait until the transaction ends - while (_spi_info.spi_state != eSPI_STATE_IDLE); - - return 0; -} - -void cc3000_spi::write_synchronous(uint8_t *data, uint16_t size) { - while(size) - { - _wlan_spi.write(*data++); - size--; - } -} - -void cc3000_spi::read_synchronous(uint8_t *data, uint16_t size) { - for (uint32_t i = 0; i < size; i++) - { - data[i] = _wlan_spi.write(0x03);; - } -} - -uint32_t cc3000_spi::read_data_cont() { - long data_to_recv; - unsigned char *evnt_buff, type; - - //determine the packet type - evnt_buff = _simple_link.get_received_buffer(); - data_to_recv = 0; - STREAM_TO_UINT8((uint8_t *)(evnt_buff + SPI_HEADER_SIZE), HCI_PACKET_TYPE_OFFSET, type); - - switch(type) - { - case HCI_TYPE_DATA: - { - // Read the remaining data.. - STREAM_TO_UINT16((uint8_t *)(evnt_buff + SPI_HEADER_SIZE), HCI_DATA_LENGTH_OFFSET, data_to_recv); - if (!((HEADERS_SIZE_EVNT + data_to_recv) & 1)) - { - data_to_recv++; - } - - if (data_to_recv) - { - read_synchronous(evnt_buff + 10, data_to_recv); - } - break; - } - case HCI_TYPE_EVNT: - { - // Calculate the rest length of the data - STREAM_TO_UINT8((char *)(evnt_buff + SPI_HEADER_SIZE), HCI_EVENT_LENGTH_OFFSET, data_to_recv); - data_to_recv -= 1; - // Add padding byte if needed - if ((HEADERS_SIZE_EVNT + data_to_recv) & 1) - { - data_to_recv++; - } - - if (data_to_recv) - { - read_synchronous(evnt_buff + 10, data_to_recv); - } - - _spi_info.spi_state = eSPI_STATE_READ_EOT; - break; - } - } - return (0); -} - -void cc3000_spi::write_wlan_en(uint8_t value) { - if (value) { - _wlan_en = 1; - } else { - _wlan_en = 0; - } -} - -void cc3000_spi::WLAN_IRQHandler() { - if (_spi_info.spi_state == eSPI_STATE_POWERUP) - { - // Inform HCI Layer that IRQ occured after powerup - _spi_info.spi_state = eSPI_STATE_INITIALIZED; - } - else if (_spi_info.spi_state == eSPI_STATE_IDLE) - { - _spi_info.spi_state = eSPI_STATE_READ_IRQ; - /* IRQ line goes low - acknowledge it */ - _wlan_cs = 0; - read_synchronous(_simple_link.get_received_buffer(), 10); - _spi_info.spi_state = eSPI_STATE_READ_EOT; - - - // The header was read - continue with the payload read - if (!read_data_cont()) - { - // All the data was read - finalize handling by switching to the task - // Trigger Rx processing - wlan_irq_disable(); - _wlan_cs = 1; - // The magic number resides at the end of the TX/RX buffer (1 byte after the allocated size) - // If the magic number is overwitten - buffer overrun occurred - we will be stuck here forever! - uint8_t *received_buffer = _simple_link.get_received_buffer(); - if (received_buffer[CC3000_RX_BUFFER_SIZE - 1] != CC3000_BUFFER_MAGIC_NUMBER) - { - while (1); - } - _spi_info.spi_state = eSPI_STATE_IDLE; - _event.received_handler(received_buffer + SPI_HEADER_SIZE); - } - } - else if (_spi_info.spi_state == eSPI_STATE_WRITE_IRQ) - { - write_synchronous(_simple_link.get_transmit_buffer(), _spi_info.tx_packet_length); - _spi_info.spi_state = eSPI_STATE_IDLE; - _wlan_cs = 1; - } -} - -} +/***************************************************************************** +* +* C++ interface/implementation created by Martin Kojtal (0xc0170). Thanks to +* Jim Carver and Frank Vannieuwkerke for their inital cc3000 mbed port and +* provided help. +* +* This version of "host driver" uses CC3000 Host Driver Implementation. Thus +* read the following copyright: +* +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*****************************************************************************/ +#include "cc3000.h" +#include "cc3000_spi.h" + +namespace mbed_cc3000 { + +cc3000_spi::cc3000_spi(PinName cc3000_irq, PinName cc3000_en, PinName cc3000_cs, SPI cc3000_spi, IRQn_Type irq_port, cc3000_event &event, cc3000_simple_link &simple_link) + : _wlan_irq(cc3000_irq), _wlan_en(cc3000_en), _wlan_cs(cc3000_cs), _wlan_spi(cc3000_spi), _irq_port(irq_port), + _event(event), _simple_link(simple_link) { + /* TODO = clear pending interrupts for PORTS. This is dependent on the used chip */ + + _wlan_spi.format(8,1); + _wlan_spi.frequency(12000000); + _function_pointer = _wlan_irq.fall(this, &cc3000_spi::WLAN_IRQHandler); + + _wlan_en = 0; + _wlan_cs = 1; +} + +cc3000_spi::~cc3000_spi() { + +} + +void cc3000_spi::wlan_irq_enable() +{ + NVIC_EnableIRQ(_irq_port); +} + +void cc3000_spi::wlan_irq_disable() { + NVIC_DisableIRQ(_irq_port); +} + +void cc3000_spi::wlan_irq_set(uint8_t value) { + if (value) + { + _wlan_en = 1; + } + else + { + _wlan_en = 0; + } +} + +uint32_t cc3000_spi::wlan_irq_read() { + return _wlan_irq.read(); +} + +void cc3000_spi::close() { + if (_simple_link.get_received_buffer() != 0) + { + _simple_link.set_received_buffer(0); + } + wlan_irq_disable(); +} + +// void cc3000_spi::SpiReceiveHandler() { +// _simple_link.usEventOrDataReceived = 1; +// //_simple_link.pucReceivedData = (unsigned char *)pvBuffer; + +// hci_unsolicited_event_handler(); +// } + + +/* TODO + pRxPacket, pTxPacket do we need to hold this pointer ? + SPIRxHandler - remove? +*/ +void cc3000_spi::open() { + _spi_info.spi_state = eSPI_STATE_POWERUP; + //_spi_info.SPIRxHandler = pfRxHandler; + _spi_info.tx_packet_length = 0; + _spi_info.rx_packet_length = 0; + //_rx_buffer[CC3000_RX_BUFFER_SIZE - 1] = CC3000_BUFFER_MAGIC_NUMBER; + //_tx_buffer[CC3000_TX_BUFFER_SIZE - 1] = CC3000_BUFFER_MAGIC_NUMBER; + wlan_irq_enable(); +} + +uint32_t cc3000_spi::first_write(uint8_t *buffer, uint16_t length) { + _wlan_cs = 0; + wait_us(50); + + /* first 4 bytes of the data */ + write_synchronous(buffer, 4); + wait_us(50); + write_synchronous(buffer + 4, length - 4); + _spi_info.spi_state = eSPI_STATE_IDLE; + _wlan_cs = 1; + + return 0; +} + + +uint32_t cc3000_spi::write(uint8_t *buffer, uint16_t length) { + uint8_t pad = 0; + // check the total length of the packet in order to figure out if padding is necessary + if(!(length & 0x0001)) + { + pad++; + } + buffer[0] = WRITE; + buffer[1] = HI(length + pad); + buffer[2] = LO(length + pad); + buffer[3] = 0; + buffer[4] = 0; + + length += (SPI_HEADER_SIZE + pad); + + // The magic number resides at the end of the TX/RX buffer (1 byte after the allocated size) + // If the magic number is overwitten - buffer overrun occurred - we will be stuck here forever! + uint8_t * transmit_buffer = _simple_link.get_transmit_buffer(); + if (transmit_buffer[CC3000_TX_BUFFER_SIZE - 1] != CC3000_BUFFER_MAGIC_NUMBER) + { + while (1); + } + + if (_spi_info.spi_state == eSPI_STATE_POWERUP) + { + while (_spi_info.spi_state != eSPI_STATE_INITIALIZED); + } + + if (_spi_info.spi_state == eSPI_STATE_INITIALIZED) + { + // TX/RX transaction over SPI after powerup: IRQ is low - send read buffer size command + first_write(buffer, length); + } + else + { + // Prevent occurence of a race condition when 2 back to back packets are sent to the + // device, so the state will move to IDLE and once again to not IDLE due to IRQ + wlan_irq_disable(); + + while (_spi_info.spi_state != eSPI_STATE_IDLE); + + _spi_info.spi_state = eSPI_STATE_WRITE_IRQ; + //_spi_info.pTxPacket = buffer; + _spi_info.tx_packet_length = length; + + // Assert the CS line and wait until the IRQ line is active, then initialize the write operation + _wlan_cs = 0; + + wlan_irq_enable(); + } + + // Wait until the transaction ends + while (_spi_info.spi_state != eSPI_STATE_IDLE); + + return 0; +} + +void cc3000_spi::write_synchronous(uint8_t *data, uint16_t size) { + while(size) + { + _wlan_spi.write(*data++); + size--; + } +} + +void cc3000_spi::read_synchronous(uint8_t *data, uint16_t size) { + for (uint32_t i = 0; i < size; i++) + { + data[i] = _wlan_spi.write(0x03);; + } +} + +uint32_t cc3000_spi::read_data_cont() { + long data_to_recv; + unsigned char *evnt_buff, type; + + //determine the packet type + evnt_buff = _simple_link.get_received_buffer(); + data_to_recv = 0; + STREAM_TO_UINT8((uint8_t *)(evnt_buff + SPI_HEADER_SIZE), HCI_PACKET_TYPE_OFFSET, type); + + switch(type) + { + case HCI_TYPE_DATA: + { + // Read the remaining data.. + STREAM_TO_UINT16((uint8_t *)(evnt_buff + SPI_HEADER_SIZE), HCI_DATA_LENGTH_OFFSET, data_to_recv); + if (!((HEADERS_SIZE_EVNT + data_to_recv) & 1)) + { + data_to_recv++; + } + + if (data_to_recv) + { + read_synchronous(evnt_buff + 10, data_to_recv); + } + break; + } + case HCI_TYPE_EVNT: + { + // Calculate the rest length of the data + STREAM_TO_UINT8((char *)(evnt_buff + SPI_HEADER_SIZE), HCI_EVENT_LENGTH_OFFSET, data_to_recv); + data_to_recv -= 1; + // Add padding byte if needed + if ((HEADERS_SIZE_EVNT + data_to_recv) & 1) + { + data_to_recv++; + } + + if (data_to_recv) + { + read_synchronous(evnt_buff + 10, data_to_recv); + } + + _spi_info.spi_state = eSPI_STATE_READ_EOT; + break; + } + } + return (0); +} + +void cc3000_spi::write_wlan_en(uint8_t value) { + if (value) { + _wlan_en = 1; + } else { + _wlan_en = 0; + } +} + +void cc3000_spi::WLAN_IRQHandler() { + if (_spi_info.spi_state == eSPI_STATE_POWERUP) + { + // Inform HCI Layer that IRQ occured after powerup + _spi_info.spi_state = eSPI_STATE_INITIALIZED; + } + else if (_spi_info.spi_state == eSPI_STATE_IDLE) + { + _spi_info.spi_state = eSPI_STATE_READ_IRQ; + /* IRQ line goes low - acknowledge it */ + _wlan_cs = 0; + read_synchronous(_simple_link.get_received_buffer(), 10); + _spi_info.spi_state = eSPI_STATE_READ_EOT; + + + // The header was read - continue with the payload read + if (!read_data_cont()) + { + // All the data was read - finalize handling by switching to the task + // Trigger Rx processing + wlan_irq_disable(); + _wlan_cs = 1; + // The magic number resides at the end of the TX/RX buffer (1 byte after the allocated size) + // If the magic number is overwitten - buffer overrun occurred - we will be stuck here forever! + uint8_t *received_buffer = _simple_link.get_received_buffer(); + if (received_buffer[CC3000_RX_BUFFER_SIZE - 1] != CC3000_BUFFER_MAGIC_NUMBER) + { + while (1); + } + _spi_info.spi_state = eSPI_STATE_IDLE; + _event.received_handler(received_buffer + SPI_HEADER_SIZE); + } + } + else if (_spi_info.spi_state == eSPI_STATE_WRITE_IRQ) + { + write_synchronous(_simple_link.get_transmit_buffer(), _spi_info.tx_packet_length); + _spi_info.spi_state = eSPI_STATE_IDLE; + _wlan_cs = 1; + } +} + +}