Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of cc3000_hostdriver_mbedsocket by
cc3000_wlan.cpp
- Committer:
- SolderSplashLabs
- Date:
- 2013-10-03
- Revision:
- 23:fed7f64dd520
- Parent:
- 0:615c697c33b0
- Child:
- 33:9e23b24fb4f3
File content as of revision 23:fed7f64dd520:
/*****************************************************************************
*
* 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
}
