version_2.0
Dependents: cc3000_ping_demo_try_2
Fork of cc3000_hostdriver_mbedsocket by
Diff: cc3000_wlan.cpp
- Revision:
- 20:30b6ed7bf8fd
- Parent:
- 0:615c697c33b0
- Child:
- 33:9e23b24fb4f3
--- a/cc3000_wlan.cpp Thu Oct 03 09:49:03 2013 +0200 +++ b/cc3000_wlan.cpp Thu Oct 03 17:15:45 2013 +0200 @@ -1,699 +1,699 @@ -/***************************************************************************** -* -* 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" - -namespace mbed_cc3000 { - -cc3000_wlan::cc3000_wlan(cc3000_simple_link &simple_link, cc3000_event &event, cc3000_spi &spi, cc3000_hci &hci) : - _simple_link(simple_link), _event(event), _spi(spi), _hci(hci) { - -} - -cc3000_wlan::~cc3000_wlan() { - -} - -void cc3000_wlan::simpleLink_init_start(uint16_t patches_available_host) { - uint8_t *ptr; - uint8_t *args; - - ptr = _simple_link.get_transmit_buffer(); - args = (uint8_t *)(ptr + HEADERS_SIZE_CMD); - - UINT8_TO_STREAM(args, ((patches_available_host) ? SL_PATCHES_REQUEST_FORCE_HOST : SL_PATCHES_REQUEST_DEFAULT)); - - // IRQ Line asserted - send HCI_CMND_SIMPLE_LINK_START to CC3000 - _hci.command_send(HCI_CMND_SIMPLE_LINK_START, ptr, WLAN_SL_INIT_START_PARAMS_LEN); - _event.simplelink_wait_event(HCI_CMND_SIMPLE_LINK_START, 0); -} - -void cc3000_wlan::start(uint16_t patches_available_host) { - uint32_t spi_irq_state; - - _simple_link.set_sent_packets(0); - _simple_link.set_number_of_released_packets(0); - _simple_link.set_op_code(0); - _simple_link.set_number_free_buffers(0); - _simple_link.set_buffer_length(0); - _simple_link.set_buffer_size(0); - _simple_link.set_pending_data(0); - _simple_link.set_transmit_error(0); - _simple_link.set_data_received_flag(0); - _simple_link.set_buffer_size(0); - - // init spi - _spi.open(); - // Check the IRQ line - spi_irq_state = _spi.wlan_irq_read(); - // ASIC 1273 chip enable: toggle WLAN EN line - _spi.write_wlan_en(WLAN_ENABLE); - - if (spi_irq_state) - { - // wait till the IRQ line goes low - while(_spi.wlan_irq_read() != 0) - { - } - } - else - { - // wait till the IRQ line goes high and then low - while(_spi.wlan_irq_read() == 0) - { - } - while(_spi.wlan_irq_read() != 0) - { - } - } - simpleLink_init_start(patches_available_host); - - // Read Buffer's size and finish - _hci.command_send(HCI_CMND_READ_BUFFER_SIZE, _simple_link.get_transmit_buffer(), 0); - _event.simplelink_wait_event(HCI_CMND_READ_BUFFER_SIZE, 0); -} - - -void cc3000_wlan::stop() { - // ASIC 1273 chip disable - _spi.write_wlan_en( WLAN_DISABLE ); - - // Wait till IRQ line goes high... - while(_spi.wlan_irq_read() == 0) - { - } - - // Free the used by WLAN Driver memory - if (_simple_link.get_transmit_buffer()) - { - _simple_link.set_transmit_buffer(0); - } - - _spi.close(); -} - - -int32_t cc3000_wlan::disconnect() { - int32_t ret; - uint8_t *ptr; - - ret = EFAIL; - ptr = _simple_link.get_transmit_buffer(); - - _hci.command_send(HCI_CMND_WLAN_DISCONNECT, ptr, 0); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_WLAN_DISCONNECT, &ret); - errno = ret; - - return(ret); -} - - -int32_t cc3000_wlan::ioctl_set_connection_policy(uint32_t should_connect_to_open_ap, - uint32_t use_fast_connect, - uint32_t use_profiles) { - int32_t ret; - uint8_t *ptr; - uint8_t *args; - - ret = EFAIL; - ptr = _simple_link.get_transmit_buffer(); - args = (uint8_t *)(ptr + HEADERS_SIZE_CMD); - - // Fill in HCI packet structure - args = UINT32_TO_STREAM(args, should_connect_to_open_ap); - args = UINT32_TO_STREAM(args, use_fast_connect); - args = UINT32_TO_STREAM(args, use_profiles); - - // Initiate a HCI command - _hci.command_send(HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY, ptr, WLAN_SET_CONNECTION_POLICY_PARAMS_LEN); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY, &ret); - - return(ret); -} - - -int32_t cc3000_wlan::ioctl_del_profile(uint32_t index) { - int32_t ret; - uint8_t *ptr; - uint8_t *args; - - ptr = _simple_link.get_transmit_buffer(); - args = (uint8_t *)(ptr + HEADERS_SIZE_CMD); - - // Fill in HCI packet structure - args = UINT32_TO_STREAM(args, index); - ret = EFAIL; - - // Initiate a HCI command - _hci.command_send(HCI_CMND_WLAN_IOCTL_DEL_PROFILE, ptr, WLAN_DEL_PROFILE_PARAMS_LEN); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_DEL_PROFILE, &ret); - - return(ret); -} - -int32_t cc3000_wlan::set_event_mask(uint32_t mask) { - int32_t ret; - uint8_t *ptr; - uint8_t *args; - - - if ((mask & HCI_EVNT_WLAN_TX_COMPLETE) == HCI_EVNT_WLAN_TX_COMPLETE) - { - _simple_link.set_tx_complete_signal(0); - - // Since an event is a virtual event - i.e. it is not coming from CC3000 - // there is no need to send anything to the device if it was an only event - if (mask == HCI_EVNT_WLAN_TX_COMPLETE) - { - return 0; - } - - mask &= ~HCI_EVNT_WLAN_TX_COMPLETE; - mask |= HCI_EVNT_WLAN_UNSOL_BASE; - } - else - { - _simple_link.set_tx_complete_signal(1); - } - - ret = EFAIL; - ptr = _simple_link.get_transmit_buffer(); - args = (uint8_t *)(ptr + HEADERS_SIZE_CMD); - - // Fill in HCI packet structure - args = UINT32_TO_STREAM(args, mask); - - // Initiate a HCI command - _hci.command_send(HCI_CMND_EVENT_MASK, ptr, WLAN_SET_MASK_PARAMS_LEN); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_EVENT_MASK, &ret); - - return(ret); -} - - -int32_t cc3000_wlan::smart_config_start(uint32_t encrypted_flag) { - int32_t ret; - uint8_t *ptr; - uint8_t *args; - - ret = EFAIL; - ptr = _simple_link.get_transmit_buffer(); - args = (uint8_t *)(ptr + HEADERS_SIZE_CMD); - - // Fill in HCI packet structure - args = UINT32_TO_STREAM(args, encrypted_flag); - ret = EFAIL; - - _hci.command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START, ptr, WLAN_SMART_CONFIG_START_PARAMS_LEN); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START, &ret); - - return(ret); -} - - -int32_t cc3000_wlan::smart_config_stop(void) { - int32_t ret; - uint8_t *ptr; - - ret = EFAIL; - ptr = _simple_link.get_transmit_buffer(); - - _hci.command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP, ptr, 0); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP, &ret); - - return(ret); -} - -int32_t cc3000_wlan::smart_config_set_prefix(uint8_t *new_prefix) { - int32_t ret; - uint8_t *ptr; - uint8_t *args; - - ret = EFAIL; - ptr = _simple_link.get_transmit_buffer(); - args = (ptr + HEADERS_SIZE_CMD); - - if (new_prefix == NULL) - return ret; - else // with the new Smart Config, prefix must be TTT - { - *new_prefix = 'T'; - *(new_prefix + 1) = 'T'; - *(new_prefix + 2) = 'T'; - } - - ARRAY_TO_STREAM(args, new_prefix, SL_SIMPLE_CONFIG_PREFIX_LENGTH); - - _hci.command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_SET_PREFIX, ptr, SL_SIMPLE_CONFIG_PREFIX_LENGTH); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_SET_PREFIX, &ret); - - return(ret); -} - -#ifndef CC3000_TINY_DRIVER -int32_t cc3000_wlan::connect(uint32_t sec_type, const uint8_t *ssid, int32_t ssid_len, uint8_t *bssid, - uint8_t *key, int32_t key_len) { - int32_t ret; - uint8_t *ptr; - uint8_t *args; - uint8_t bssid_zero[] = {0, 0, 0, 0, 0, 0}; - - ret = EFAIL; - ptr = _simple_link.get_transmit_buffer(); - args = (ptr + HEADERS_SIZE_CMD); - - // Fill in command buffer - args = UINT32_TO_STREAM(args, 0x0000001c); - args = UINT32_TO_STREAM(args, ssid_len); - args = UINT32_TO_STREAM(args, sec_type); - args = UINT32_TO_STREAM(args, 0x00000010 + ssid_len); - args = UINT32_TO_STREAM(args, key_len); - args = UINT16_TO_STREAM(args, 0); - - // padding shall be zeroed - if(bssid) - { - ARRAY_TO_STREAM(args, bssid, ETH_ALEN); - } - else - { - ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); - } - - ARRAY_TO_STREAM(args, ssid, ssid_len); - - if(key_len && key) - { - ARRAY_TO_STREAM(args, key, key_len); - } - - // Initiate a HCI command - _hci.command_send(HCI_CMND_WLAN_CONNECT, ptr, WLAN_CONNECT_PARAM_LEN + ssid_len + key_len - 1); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_WLAN_CONNECT, &ret); - errno = ret; - - return(ret); -} - -int32_t cc3000_wlan::add_profile(uint32_t sec_type, - uint8_t* ssid, - uint32_t ssid_length, - uint8_t *b_ssid, - uint32_t priority, - uint32_t pairwise_cipher_or_tx_key_len, - uint32_t group_cipher_tx_key_index, - uint32_t key_mgmt, - uint8_t* pf_or_key, - uint32_t pass_phrase_len) { - uint16_t arg_len = 0x00; - int32_t ret; - uint8_t *ptr; - int32_t i = 0; - uint8_t *args; - uint8_t bssid_zero[] = {0, 0, 0, 0, 0, 0}; - - ptr = _simple_link.get_transmit_buffer(); - args = (ptr + HEADERS_SIZE_CMD); - - args = UINT32_TO_STREAM(args, sec_type); - - // Setup arguments in accordance with the security type - switch (sec_type) - { - //OPEN - case WLAN_SEC_UNSEC: - { - args = UINT32_TO_STREAM(args, 0x00000014); - args = UINT32_TO_STREAM(args, ssid_length); - args = UINT16_TO_STREAM(args, 0); - if(b_ssid) - { - ARRAY_TO_STREAM(args, b_ssid, ETH_ALEN); - } - else - { - ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); - } - args = UINT32_TO_STREAM(args, priority); - ARRAY_TO_STREAM(args, ssid, ssid_length); - - arg_len = WLAN_ADD_PROFILE_NOSEC_PARAM_LEN + ssid_length; - } - break; - - //WEP - case WLAN_SEC_WEP: - { - args = UINT32_TO_STREAM(args, 0x00000020); - args = UINT32_TO_STREAM(args, ssid_length); - args = UINT16_TO_STREAM(args, 0); - if(b_ssid) - { - ARRAY_TO_STREAM(args, b_ssid, ETH_ALEN); - } - else - { - ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); - } - args = UINT32_TO_STREAM(args, priority); - args = UINT32_TO_STREAM(args, 0x0000000C + ssid_length); - args = UINT32_TO_STREAM(args, pairwise_cipher_or_tx_key_len); - args = UINT32_TO_STREAM(args, group_cipher_tx_key_index); - ARRAY_TO_STREAM(args, ssid, ssid_length); - - for(i = 0; i < 4; i++) - { - uint8_t *p = &pf_or_key[i * pairwise_cipher_or_tx_key_len]; - - ARRAY_TO_STREAM(args, p, pairwise_cipher_or_tx_key_len); - } - - arg_len = WLAN_ADD_PROFILE_WEP_PARAM_LEN + ssid_length + - pairwise_cipher_or_tx_key_len * 4; - - } - break; - - //WPA - //WPA2 - case WLAN_SEC_WPA: - case WLAN_SEC_WPA2: - { - args = UINT32_TO_STREAM(args, 0x00000028); - args = UINT32_TO_STREAM(args, ssid_length); - args = UINT16_TO_STREAM(args, 0); - if(b_ssid) - { - ARRAY_TO_STREAM(args, b_ssid, ETH_ALEN); - } - else - { - ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); - } - args = UINT32_TO_STREAM(args, priority); - args = UINT32_TO_STREAM(args, pairwise_cipher_or_tx_key_len); - args = UINT32_TO_STREAM(args, group_cipher_tx_key_index); - args = UINT32_TO_STREAM(args, key_mgmt); - args = UINT32_TO_STREAM(args, 0x00000008 + ssid_length); - args = UINT32_TO_STREAM(args, pass_phrase_len); - ARRAY_TO_STREAM(args, ssid, ssid_length); - ARRAY_TO_STREAM(args, pf_or_key, pass_phrase_len); - - arg_len = WLAN_ADD_PROFILE_WPA_PARAM_LEN + ssid_length + pass_phrase_len; - } - - break; - } - - // Initiate a HCI command - _hci.command_send(HCI_CMND_WLAN_IOCTL_ADD_PROFILE, ptr, arg_len); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_ADD_PROFILE, &ret); - - return(ret); -} - -int32_t cc3000_wlan::ioctl_get_scan_results(uint32_t scan_timeout, uint8_t *results) { - uint8_t *ptr; - uint8_t *args; - - ptr = _simple_link.get_transmit_buffer(); - args = (ptr + HEADERS_SIZE_CMD); - - // Fill in temporary command buffer - args = UINT32_TO_STREAM(args, scan_timeout); - - // Initiate a HCI command - _hci.command_send(HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS, ptr, WLAN_GET_SCAN_RESULTS_PARAMS_LEN); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS, results); - - return(0); -} - -int32_t cc3000_wlan::ioctl_set_scan_params(uint32_t enable, - uint32_t min_dwell_time, - uint32_t max_dwell_time, - uint32_t num_probe_requests, - uint32_t channel_mask, - int32_t rssi_threshold, - uint32_t snr_threshold, - uint32_t default_tx_power, - uint32_t *interval_list) { - uint32_t uiRes; - uint8_t *ptr; - uint8_t *args; - - ptr = _simple_link.get_transmit_buffer(); - args = (ptr + HEADERS_SIZE_CMD); - - // Fill in temporary command buffer - args = UINT32_TO_STREAM(args, 36); - args = UINT32_TO_STREAM(args, enable); - args = UINT32_TO_STREAM(args, min_dwell_time); - args = UINT32_TO_STREAM(args, max_dwell_time); - args = UINT32_TO_STREAM(args, num_probe_requests); - args = UINT32_TO_STREAM(args, channel_mask); - args = UINT32_TO_STREAM(args, rssi_threshold); - args = UINT32_TO_STREAM(args, snr_threshold); - args = UINT32_TO_STREAM(args, default_tx_power); - ARRAY_TO_STREAM(args, interval_list, sizeof(uint32_t) * SL_SET_SCAN_PARAMS_INTERVAL_LIST_SIZE); - - // Initiate a HCI command - _hci.command_send(HCI_CMND_WLAN_IOCTL_SET_SCANPARAM, ptr, WLAN_SET_SCAN_PARAMS_LEN); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_SET_SCANPARAM, &uiRes); - - return(uiRes); -} - -int32_t cc3000_wlan::ioctl_statusget(void) { - int32_t ret; - uint8_t *ptr; - - ret = EFAIL; - ptr = _simple_link.get_transmit_buffer(); - - _hci.command_send(HCI_CMND_WLAN_IOCTL_STATUSGET,ptr, 0); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_STATUSGET, &ret); - - return(ret); -} - -#else -int32_t cc3000_wlan::wlan_add_profile(uint32_t sec_type, - uint8_t *ssid, - uint32_t ssid_length, - uint8_t *b_ssid, - uint32_t priority, - uint32_t pairwise_cipher_or_tx_key_len, - uint32_t group_cipher_tx_key_index, - uint32_t key_mgmt, - uint8_t* pf_or_key, - uint32_t pass_phrase_length) -{ - return -1; -} - -int32_t cc3000_wlan::connect(const uint8_t *ssid, int32_t ssid_len) { - int32_t ret; - uint8_t *ptr; - uint8_t *args; - uint8_t bssid_zero[] = {0, 0, 0, 0, 0, 0}; - - ret = EFAIL; - ptr = _simple_link.get_transmit_buffer(); - args = (ptr + HEADERS_SIZE_CMD); - - // Fill in command buffer - args = UINT32_TO_STREAM(args, 0x0000001c); - args = UINT32_TO_STREAM(args, ssid_len); - args = UINT32_TO_STREAM(args, 0); - args = UINT32_TO_STREAM(args, 0x00000010 + ssid_len); - args = UINT32_TO_STREAM(args, 0); - args = UINT16_TO_STREAM(args, 0); - - // padding shall be zeroed - ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); - ARRAY_TO_STREAM(args, ssid, ssid_len); - - // Initiate a HCI command - _hci.command_send(HCI_CMND_WLAN_CONNECT, ptr, WLAN_CONNECT_PARAM_LEN + ssid_len - 1); - - // Wait for command complete event - _event.simplelink_wait_event(HCI_CMND_WLAN_CONNECT, &ret); - errno = ret; - - return(ret); -} -#endif - - - -#ifndef CC3000_UNENCRYPTED_SMART_CONFIG -int32_t cc3000_wlan::smart_config_process(void) { - int32_t returnValue; - uint32_t ssidLen, keyLen; - uint8_t *decKeyPtr; - uint8_t *ssidPtr; - - // read the key from EEPROM - fileID 12 - returnValue = aes_read_key(key); - - if (returnValue != 0) - return returnValue; - - // read the received data from fileID #13 and parse it according to the followings: - // 1) SSID LEN - not encrypted - // 2) SSID - not encrypted - // 3) KEY LEN - not encrypted. always 32 bytes long - // 4) Security type - not encrypted - // 5) KEY - encrypted together with true key length as the first byte in KEY - // to elaborate, there are two corner cases: - // 1) the KEY is 32 bytes long. In this case, the first byte does not represent KEY length - // 2) the KEY is 31 bytes long. In this case, the first byte represent KEY length and equals 31 - returnValue = nvmem_read(NVMEM_SHARED_MEM_FILEID, SMART_CONFIG_PROFILE_SIZE, 0, profileArray); - - if (returnValue != 0) - return returnValue; - - ssidPtr = &profileArray[1]; - - ssidLen = profileArray[0]; - - decKeyPtr = &profileArray[profileArray[0] + 3]; - - aes_decrypt(decKeyPtr, key); - if (profileArray[profileArray[0] + 1] > 16) - aes_decrypt((uint8_t *)(decKeyPtr + 16), key); - - if (*(uint8_t *)(decKeyPtr +31) != 0) - { - if (*decKeyPtr == 31) - { - keyLen = 31; - decKeyPtr++; - } - else - { - keyLen = 32; - } - } - else - { - keyLen = *decKeyPtr; - decKeyPtr++; - } - - // add a profile - switch (profileArray[profileArray[0] + 2]) - { - case WLAN_SEC_UNSEC://None - { - returnValue = wlan_add_profile(profileArray[profileArray[0] + 2], // security type - ssidPtr, // SSID - ssidLen, // SSID length - NULL, // BSSID - 1, // Priority - 0, 0, 0, 0, 0); - - break; - } - - case WLAN_SEC_WEP://WEP - { - returnValue = wlan_add_profile(profileArray[profileArray[0] + 2], // security type - ssidPtr, // SSID - ssidLen, // SSID length - NULL, // BSSID - 1, // Priority - keyLen, // KEY length - 0, // KEY index - 0, - decKeyPtr, // KEY - 0); - - break; - } - - case WLAN_SEC_WPA: //WPA - case WLAN_SEC_WPA2: //WPA2 - { - returnValue = wlan_add_profile(WLAN_SEC_WPA2, // security type - ssidPtr, - ssidLen, - NULL, // BSSID - 1, // Priority - 0x18, // PairwiseCipher - 0x1e, // GroupCipher - 2, // KEY management - decKeyPtr, // KEY - keyLen); // KEY length - - break; - } - } - - return returnValue; -} -#endif - -} +/***************************************************************************** +* +* 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" + +namespace mbed_cc3000 { + +cc3000_wlan::cc3000_wlan(cc3000_simple_link &simple_link, cc3000_event &event, cc3000_spi &spi, cc3000_hci &hci) : + _simple_link(simple_link), _event(event), _spi(spi), _hci(hci) { + +} + +cc3000_wlan::~cc3000_wlan() { + +} + +void cc3000_wlan::simpleLink_init_start(uint16_t patches_available_host) { + uint8_t *ptr; + uint8_t *args; + + ptr = _simple_link.get_transmit_buffer(); + args = (uint8_t *)(ptr + HEADERS_SIZE_CMD); + + UINT8_TO_STREAM(args, ((patches_available_host) ? SL_PATCHES_REQUEST_FORCE_HOST : SL_PATCHES_REQUEST_DEFAULT)); + + // IRQ Line asserted - send HCI_CMND_SIMPLE_LINK_START to CC3000 + _hci.command_send(HCI_CMND_SIMPLE_LINK_START, ptr, WLAN_SL_INIT_START_PARAMS_LEN); + _event.simplelink_wait_event(HCI_CMND_SIMPLE_LINK_START, 0); +} + +void cc3000_wlan::start(uint16_t patches_available_host) { + uint32_t spi_irq_state; + + _simple_link.set_sent_packets(0); + _simple_link.set_number_of_released_packets(0); + _simple_link.set_op_code(0); + _simple_link.set_number_free_buffers(0); + _simple_link.set_buffer_length(0); + _simple_link.set_buffer_size(0); + _simple_link.set_pending_data(0); + _simple_link.set_transmit_error(0); + _simple_link.set_data_received_flag(0); + _simple_link.set_buffer_size(0); + + // init spi + _spi.open(); + // Check the IRQ line + spi_irq_state = _spi.wlan_irq_read(); + // ASIC 1273 chip enable: toggle WLAN EN line + _spi.write_wlan_en(WLAN_ENABLE); + + if (spi_irq_state) + { + // wait till the IRQ line goes low + while(_spi.wlan_irq_read() != 0) + { + } + } + else + { + // wait till the IRQ line goes high and then low + while(_spi.wlan_irq_read() == 0) + { + } + while(_spi.wlan_irq_read() != 0) + { + } + } + simpleLink_init_start(patches_available_host); + + // Read Buffer's size and finish + _hci.command_send(HCI_CMND_READ_BUFFER_SIZE, _simple_link.get_transmit_buffer(), 0); + _event.simplelink_wait_event(HCI_CMND_READ_BUFFER_SIZE, 0); +} + + +void cc3000_wlan::stop() { + // ASIC 1273 chip disable + _spi.write_wlan_en( WLAN_DISABLE ); + + // Wait till IRQ line goes high... + while(_spi.wlan_irq_read() == 0) + { + } + + // Free the used by WLAN Driver memory + if (_simple_link.get_transmit_buffer()) + { + _simple_link.set_transmit_buffer(0); + } + + _spi.close(); +} + + +int32_t cc3000_wlan::disconnect() { + int32_t ret; + uint8_t *ptr; + + ret = EFAIL; + ptr = _simple_link.get_transmit_buffer(); + + _hci.command_send(HCI_CMND_WLAN_DISCONNECT, ptr, 0); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_WLAN_DISCONNECT, &ret); + errno = ret; + + return(ret); +} + + +int32_t cc3000_wlan::ioctl_set_connection_policy(uint32_t should_connect_to_open_ap, + uint32_t use_fast_connect, + uint32_t use_profiles) { + int32_t ret; + uint8_t *ptr; + uint8_t *args; + + ret = EFAIL; + ptr = _simple_link.get_transmit_buffer(); + args = (uint8_t *)(ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, should_connect_to_open_ap); + args = UINT32_TO_STREAM(args, use_fast_connect); + args = UINT32_TO_STREAM(args, use_profiles); + + // Initiate a HCI command + _hci.command_send(HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY, ptr, WLAN_SET_CONNECTION_POLICY_PARAMS_LEN); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY, &ret); + + return(ret); +} + + +int32_t cc3000_wlan::ioctl_del_profile(uint32_t index) { + int32_t ret; + uint8_t *ptr; + uint8_t *args; + + ptr = _simple_link.get_transmit_buffer(); + args = (uint8_t *)(ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, index); + ret = EFAIL; + + // Initiate a HCI command + _hci.command_send(HCI_CMND_WLAN_IOCTL_DEL_PROFILE, ptr, WLAN_DEL_PROFILE_PARAMS_LEN); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_DEL_PROFILE, &ret); + + return(ret); +} + +int32_t cc3000_wlan::set_event_mask(uint32_t mask) { + int32_t ret; + uint8_t *ptr; + uint8_t *args; + + + if ((mask & HCI_EVNT_WLAN_TX_COMPLETE) == HCI_EVNT_WLAN_TX_COMPLETE) + { + _simple_link.set_tx_complete_signal(0); + + // Since an event is a virtual event - i.e. it is not coming from CC3000 + // there is no need to send anything to the device if it was an only event + if (mask == HCI_EVNT_WLAN_TX_COMPLETE) + { + return 0; + } + + mask &= ~HCI_EVNT_WLAN_TX_COMPLETE; + mask |= HCI_EVNT_WLAN_UNSOL_BASE; + } + else + { + _simple_link.set_tx_complete_signal(1); + } + + ret = EFAIL; + ptr = _simple_link.get_transmit_buffer(); + args = (uint8_t *)(ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, mask); + + // Initiate a HCI command + _hci.command_send(HCI_CMND_EVENT_MASK, ptr, WLAN_SET_MASK_PARAMS_LEN); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_EVENT_MASK, &ret); + + return(ret); +} + + +int32_t cc3000_wlan::smart_config_start(uint32_t encrypted_flag) { + int32_t ret; + uint8_t *ptr; + uint8_t *args; + + ret = EFAIL; + ptr = _simple_link.get_transmit_buffer(); + args = (uint8_t *)(ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, encrypted_flag); + ret = EFAIL; + + _hci.command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START, ptr, WLAN_SMART_CONFIG_START_PARAMS_LEN); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START, &ret); + + return(ret); +} + + +int32_t cc3000_wlan::smart_config_stop(void) { + int32_t ret; + uint8_t *ptr; + + ret = EFAIL; + ptr = _simple_link.get_transmit_buffer(); + + _hci.command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP, ptr, 0); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP, &ret); + + return(ret); +} + +int32_t cc3000_wlan::smart_config_set_prefix(uint8_t *new_prefix) { + int32_t ret; + uint8_t *ptr; + uint8_t *args; + + ret = EFAIL; + ptr = _simple_link.get_transmit_buffer(); + args = (ptr + HEADERS_SIZE_CMD); + + if (new_prefix == NULL) + return ret; + else // with the new Smart Config, prefix must be TTT + { + *new_prefix = 'T'; + *(new_prefix + 1) = 'T'; + *(new_prefix + 2) = 'T'; + } + + ARRAY_TO_STREAM(args, new_prefix, SL_SIMPLE_CONFIG_PREFIX_LENGTH); + + _hci.command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_SET_PREFIX, ptr, SL_SIMPLE_CONFIG_PREFIX_LENGTH); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_SET_PREFIX, &ret); + + return(ret); +} + +#ifndef CC3000_TINY_DRIVER +int32_t cc3000_wlan::connect(uint32_t sec_type, const uint8_t *ssid, int32_t ssid_len, uint8_t *bssid, + uint8_t *key, int32_t key_len) { + int32_t ret; + uint8_t *ptr; + uint8_t *args; + uint8_t bssid_zero[] = {0, 0, 0, 0, 0, 0}; + + ret = EFAIL; + ptr = _simple_link.get_transmit_buffer(); + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in command buffer + args = UINT32_TO_STREAM(args, 0x0000001c); + args = UINT32_TO_STREAM(args, ssid_len); + args = UINT32_TO_STREAM(args, sec_type); + args = UINT32_TO_STREAM(args, 0x00000010 + ssid_len); + args = UINT32_TO_STREAM(args, key_len); + args = UINT16_TO_STREAM(args, 0); + + // padding shall be zeroed + if(bssid) + { + ARRAY_TO_STREAM(args, bssid, ETH_ALEN); + } + else + { + ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); + } + + ARRAY_TO_STREAM(args, ssid, ssid_len); + + if(key_len && key) + { + ARRAY_TO_STREAM(args, key, key_len); + } + + // Initiate a HCI command + _hci.command_send(HCI_CMND_WLAN_CONNECT, ptr, WLAN_CONNECT_PARAM_LEN + ssid_len + key_len - 1); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_WLAN_CONNECT, &ret); + errno = ret; + + return(ret); +} + +int32_t cc3000_wlan::add_profile(uint32_t sec_type, + uint8_t* ssid, + uint32_t ssid_length, + uint8_t *b_ssid, + uint32_t priority, + uint32_t pairwise_cipher_or_tx_key_len, + uint32_t group_cipher_tx_key_index, + uint32_t key_mgmt, + uint8_t* pf_or_key, + uint32_t pass_phrase_len) { + uint16_t arg_len = 0x00; + int32_t ret; + uint8_t *ptr; + int32_t i = 0; + uint8_t *args; + uint8_t bssid_zero[] = {0, 0, 0, 0, 0, 0}; + + ptr = _simple_link.get_transmit_buffer(); + args = (ptr + HEADERS_SIZE_CMD); + + args = UINT32_TO_STREAM(args, sec_type); + + // Setup arguments in accordance with the security type + switch (sec_type) + { + //OPEN + case WLAN_SEC_UNSEC: + { + args = UINT32_TO_STREAM(args, 0x00000014); + args = UINT32_TO_STREAM(args, ssid_length); + args = UINT16_TO_STREAM(args, 0); + if(b_ssid) + { + ARRAY_TO_STREAM(args, b_ssid, ETH_ALEN); + } + else + { + ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); + } + args = UINT32_TO_STREAM(args, priority); + ARRAY_TO_STREAM(args, ssid, ssid_length); + + arg_len = WLAN_ADD_PROFILE_NOSEC_PARAM_LEN + ssid_length; + } + break; + + //WEP + case WLAN_SEC_WEP: + { + args = UINT32_TO_STREAM(args, 0x00000020); + args = UINT32_TO_STREAM(args, ssid_length); + args = UINT16_TO_STREAM(args, 0); + if(b_ssid) + { + ARRAY_TO_STREAM(args, b_ssid, ETH_ALEN); + } + else + { + ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); + } + args = UINT32_TO_STREAM(args, priority); + args = UINT32_TO_STREAM(args, 0x0000000C + ssid_length); + args = UINT32_TO_STREAM(args, pairwise_cipher_or_tx_key_len); + args = UINT32_TO_STREAM(args, group_cipher_tx_key_index); + ARRAY_TO_STREAM(args, ssid, ssid_length); + + for(i = 0; i < 4; i++) + { + uint8_t *p = &pf_or_key[i * pairwise_cipher_or_tx_key_len]; + + ARRAY_TO_STREAM(args, p, pairwise_cipher_or_tx_key_len); + } + + arg_len = WLAN_ADD_PROFILE_WEP_PARAM_LEN + ssid_length + + pairwise_cipher_or_tx_key_len * 4; + + } + break; + + //WPA + //WPA2 + case WLAN_SEC_WPA: + case WLAN_SEC_WPA2: + { + args = UINT32_TO_STREAM(args, 0x00000028); + args = UINT32_TO_STREAM(args, ssid_length); + args = UINT16_TO_STREAM(args, 0); + if(b_ssid) + { + ARRAY_TO_STREAM(args, b_ssid, ETH_ALEN); + } + else + { + ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); + } + args = UINT32_TO_STREAM(args, priority); + args = UINT32_TO_STREAM(args, pairwise_cipher_or_tx_key_len); + args = UINT32_TO_STREAM(args, group_cipher_tx_key_index); + args = UINT32_TO_STREAM(args, key_mgmt); + args = UINT32_TO_STREAM(args, 0x00000008 + ssid_length); + args = UINT32_TO_STREAM(args, pass_phrase_len); + ARRAY_TO_STREAM(args, ssid, ssid_length); + ARRAY_TO_STREAM(args, pf_or_key, pass_phrase_len); + + arg_len = WLAN_ADD_PROFILE_WPA_PARAM_LEN + ssid_length + pass_phrase_len; + } + + break; + } + + // Initiate a HCI command + _hci.command_send(HCI_CMND_WLAN_IOCTL_ADD_PROFILE, ptr, arg_len); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_ADD_PROFILE, &ret); + + return(ret); +} + +int32_t cc3000_wlan::ioctl_get_scan_results(uint32_t scan_timeout, uint8_t *results) { + uint8_t *ptr; + uint8_t *args; + + ptr = _simple_link.get_transmit_buffer(); + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, scan_timeout); + + // Initiate a HCI command + _hci.command_send(HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS, ptr, WLAN_GET_SCAN_RESULTS_PARAMS_LEN); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS, results); + + return(0); +} + +int32_t cc3000_wlan::ioctl_set_scan_params(uint32_t enable, + uint32_t min_dwell_time, + uint32_t max_dwell_time, + uint32_t num_probe_requests, + uint32_t channel_mask, + int32_t rssi_threshold, + uint32_t snr_threshold, + uint32_t default_tx_power, + uint32_t *interval_list) { + uint32_t uiRes; + uint8_t *ptr; + uint8_t *args; + + ptr = _simple_link.get_transmit_buffer(); + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, 36); + args = UINT32_TO_STREAM(args, enable); + args = UINT32_TO_STREAM(args, min_dwell_time); + args = UINT32_TO_STREAM(args, max_dwell_time); + args = UINT32_TO_STREAM(args, num_probe_requests); + args = UINT32_TO_STREAM(args, channel_mask); + args = UINT32_TO_STREAM(args, rssi_threshold); + args = UINT32_TO_STREAM(args, snr_threshold); + args = UINT32_TO_STREAM(args, default_tx_power); + ARRAY_TO_STREAM(args, interval_list, sizeof(uint32_t) * SL_SET_SCAN_PARAMS_INTERVAL_LIST_SIZE); + + // Initiate a HCI command + _hci.command_send(HCI_CMND_WLAN_IOCTL_SET_SCANPARAM, ptr, WLAN_SET_SCAN_PARAMS_LEN); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_SET_SCANPARAM, &uiRes); + + return(uiRes); +} + +int32_t cc3000_wlan::ioctl_statusget(void) { + int32_t ret; + uint8_t *ptr; + + ret = EFAIL; + ptr = _simple_link.get_transmit_buffer(); + + _hci.command_send(HCI_CMND_WLAN_IOCTL_STATUSGET,ptr, 0); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_WLAN_IOCTL_STATUSGET, &ret); + + return(ret); +} + +#else +int32_t cc3000_wlan::wlan_add_profile(uint32_t sec_type, + uint8_t *ssid, + uint32_t ssid_length, + uint8_t *b_ssid, + uint32_t priority, + uint32_t pairwise_cipher_or_tx_key_len, + uint32_t group_cipher_tx_key_index, + uint32_t key_mgmt, + uint8_t* pf_or_key, + uint32_t pass_phrase_length) +{ + return -1; +} + +int32_t cc3000_wlan::connect(const uint8_t *ssid, int32_t ssid_len) { + int32_t ret; + uint8_t *ptr; + uint8_t *args; + uint8_t bssid_zero[] = {0, 0, 0, 0, 0, 0}; + + ret = EFAIL; + ptr = _simple_link.get_transmit_buffer(); + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in command buffer + args = UINT32_TO_STREAM(args, 0x0000001c); + args = UINT32_TO_STREAM(args, ssid_len); + args = UINT32_TO_STREAM(args, 0); + args = UINT32_TO_STREAM(args, 0x00000010 + ssid_len); + args = UINT32_TO_STREAM(args, 0); + args = UINT16_TO_STREAM(args, 0); + + // padding shall be zeroed + ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); + ARRAY_TO_STREAM(args, ssid, ssid_len); + + // Initiate a HCI command + _hci.command_send(HCI_CMND_WLAN_CONNECT, ptr, WLAN_CONNECT_PARAM_LEN + ssid_len - 1); + + // Wait for command complete event + _event.simplelink_wait_event(HCI_CMND_WLAN_CONNECT, &ret); + errno = ret; + + return(ret); +} +#endif + + + +#ifndef CC3000_UNENCRYPTED_SMART_CONFIG +int32_t cc3000_wlan::smart_config_process(void) { + int32_t returnValue; + uint32_t ssidLen, keyLen; + uint8_t *decKeyPtr; + uint8_t *ssidPtr; + + // read the key from EEPROM - fileID 12 + returnValue = aes_read_key(key); + + if (returnValue != 0) + return returnValue; + + // read the received data from fileID #13 and parse it according to the followings: + // 1) SSID LEN - not encrypted + // 2) SSID - not encrypted + // 3) KEY LEN - not encrypted. always 32 bytes long + // 4) Security type - not encrypted + // 5) KEY - encrypted together with true key length as the first byte in KEY + // to elaborate, there are two corner cases: + // 1) the KEY is 32 bytes long. In this case, the first byte does not represent KEY length + // 2) the KEY is 31 bytes long. In this case, the first byte represent KEY length and equals 31 + returnValue = nvmem_read(NVMEM_SHARED_MEM_FILEID, SMART_CONFIG_PROFILE_SIZE, 0, profileArray); + + if (returnValue != 0) + return returnValue; + + ssidPtr = &profileArray[1]; + + ssidLen = profileArray[0]; + + decKeyPtr = &profileArray[profileArray[0] + 3]; + + aes_decrypt(decKeyPtr, key); + if (profileArray[profileArray[0] + 1] > 16) + aes_decrypt((uint8_t *)(decKeyPtr + 16), key); + + if (*(uint8_t *)(decKeyPtr +31) != 0) + { + if (*decKeyPtr == 31) + { + keyLen = 31; + decKeyPtr++; + } + else + { + keyLen = 32; + } + } + else + { + keyLen = *decKeyPtr; + decKeyPtr++; + } + + // add a profile + switch (profileArray[profileArray[0] + 2]) + { + case WLAN_SEC_UNSEC://None + { + returnValue = wlan_add_profile(profileArray[profileArray[0] + 2], // security type + ssidPtr, // SSID + ssidLen, // SSID length + NULL, // BSSID + 1, // Priority + 0, 0, 0, 0, 0); + + break; + } + + case WLAN_SEC_WEP://WEP + { + returnValue = wlan_add_profile(profileArray[profileArray[0] + 2], // security type + ssidPtr, // SSID + ssidLen, // SSID length + NULL, // BSSID + 1, // Priority + keyLen, // KEY length + 0, // KEY index + 0, + decKeyPtr, // KEY + 0); + + break; + } + + case WLAN_SEC_WPA: //WPA + case WLAN_SEC_WPA2: //WPA2 + { + returnValue = wlan_add_profile(WLAN_SEC_WPA2, // security type + ssidPtr, + ssidLen, + NULL, // BSSID + 1, // Priority + 0x18, // PairwiseCipher + 0x1e, // GroupCipher + 2, // KEY management + decKeyPtr, // KEY + keyLen); // KEY length + + break; + } + } + + return returnValue; +} +#endif + +}