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.cpp Source File

cc3000.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_event.h"
00043 
00044 namespace mbed_cc3000 {
00045 
00046 /* TODO this prefix remove? verify */
00047 static uint8_t cc3000_prefix[] = {'T', 'T', 'T'};
00048 cc3000 *cc3000::_inst;
00049 
00050 cc3000::cc3000(PinName cc3000_irq, PinName cc3000_en, PinName cc3000_cs, SPI cc3000_spi, uint32_t max_tx_size, uint32_t max_rx_size)
00051              : _event(_simple_link, _hci, _spi, *this), _socket(_simple_link, _hci, _event),
00052                _spi(cc3000_irq, cc3000_en, cc3000_cs, cc3000_spi, _event, _simple_link, max_tx_size, max_rx_size), _hci(_spi),
00053                _nvmem(_hci, _event, _simple_link), _netapp(_simple_link, _nvmem, _hci, _event),
00054                _wlan(_simple_link, _event, _spi, _hci) {
00055     _simple_link.create_txrx_buffers(max_tx_size, max_rx_size);
00056     _simple_link.set_tx_complete_signal(1);
00057     memset(&_status, 0, sizeof(_status));
00058     _inst = this;
00059 }
00060 
00061 cc3000::~cc3000() {
00062 }
00063 
00064 #if (CC3000_ETH_COMPAT == 1)
00065 cc3000::cc3000(PinName cc3000_irq, PinName cc3000_en, PinName cc3000_cs, SPI cc3000_spi, const char *ssid,
00066                const char *phrase, Security sec, bool smart_config, uint32_t max_tx_size, uint32_t max_rx_size)
00067              : _event(_simple_link, _hci, _spi, *this), _socket(_simple_link, _hci, _event),
00068                _spi(cc3000_irq, cc3000_en, cc3000_cs, cc3000_spi, _event, _simple_link, max_tx_size, max_rx_size), _hci(_spi),
00069                _nvmem(_hci, _event, _simple_link), _netapp(_simple_link, _nvmem, _hci, _event),
00070                _wlan(_simple_link, _event, _spi, _hci), _sec(sec), _smart_config(smart_config) {
00071     _simple_link.create_txrx_buffers(max_tx_size, max_rx_size);
00072     _simple_link.set_tx_complete_signal(1);
00073     memset(&_status, 0, sizeof(_status));
00074     strcpy((char *)_ssid, ssid);
00075     strcpy((char *)_phrase, phrase);
00076     _inst = this;
00077 }
00078 
00079 // Ethernet library compatible, functions return strings
00080 // Caches the ipconfig from the usync callback
00081 static char mac_addr[19]= "\0";
00082 static char ip_addr[17] = "\0";
00083 static char gateway[17] = "\0";
00084 static char networkmask[17] = "\0";
00085 
00086 void cc3000::init() {
00087     _wlan.start(0);
00088 
00089     uint32_t subnet[4] = {0};
00090     uint32_t ip[4] = {0};
00091     uint32_t getway[4] = {0};
00092     uint32_t dns[4] = {0};
00093 
00094     _netapp.dhcp(ip, subnet, getway, dns);
00095     _wlan.stop();
00096     wait(1);
00097     _wlan.start(0);
00098 
00099     _status.enabled = 1;
00100     _wlan.set_event_mask(HCI_EVNT_WLAN_UNSOL_INIT | HCI_EVNT_WLAN_KEEPALIVE);
00101 }
00102 
00103 void cc3000::init(const char *ip, const char *mask, const char *gateway) {
00104     _wlan.start(0);
00105     _netapp.dhcp((uint32_t *)ip, (uint32_t *)mask, (uint32_t *)gateway, (uint32_t *)ip); //dns = ip
00106     _wlan.stop();
00107     wait(1);
00108     _wlan.start(0);
00109 
00110     _status.enabled = 1;
00111     _wlan.set_event_mask(HCI_EVNT_WLAN_UNSOL_INIT | HCI_EVNT_WLAN_KEEPALIVE);
00112 }
00113 
00114 int cc3000::connect(unsigned int timeout_ms) {
00115     Timer t;
00116     int ret = 0;
00117 
00118     if (_smart_config == false) {
00119         _wlan.ioctl_set_connection_policy(0, 0, 0);
00120     } else {
00121         tUserFS user_info;
00122         get_user_file_info((uint8_t *)&user_info, sizeof(user_info));
00123         if (user_info.FTC == 1) {
00124             _wlan.ioctl_set_connection_policy(0, 1, 1);
00125         } else {
00126             DBG_CC("Smart config is not set. Please run the first time configuration.");
00127             return -1;
00128         }
00129     }
00130 
00131     t.start();
00132     while (is_connected() == false) {
00133         if (strlen((const char *)_phrase) < 8) {
00134             if (connect_open(_ssid)) {
00135                 break;
00136             }
00137         } else {
00138 #ifndef CC3000_TINY_DRIVER
00139             if (connect_secure(_ssid,_phrase, _sec)) {
00140                 break;
00141             }
00142 #else
00143             return -1; /* secure connection not supported with TINY_DRIVER */
00144 #endif
00145         }
00146 
00147         if (t.read_ms() > timeout_ms) {
00148             ret = -1;
00149             DBG_CC("Connection to AP failed");
00150             break;
00151         }
00152     }
00153 
00154     while (is_dhcp_configured() == false)
00155     {
00156         if (t.read_ms() > timeout_ms) {
00157             ret = -1;
00158             DBG_CC("Connection to AP failed");
00159             break;
00160         }
00161     }
00162 
00163     return ret;
00164 }
00165 
00166 char* cc3000::getMACAddress() {
00167     return mac_addr;
00168 }
00169 
00170 char* cc3000::getIPAddress() {
00171     return ip_addr;
00172 }
00173 
00174 char* cc3000::getGateway() {
00175     return gateway;
00176 }
00177 
00178 char* cc3000::getNetworkMask() {
00179     return networkmask;
00180 }
00181 
00182 int cc3000::disconnect(void){
00183     if (_wlan.disconnect()) {
00184         return -1;
00185     } else {
00186         return 0;
00187     }
00188 }
00189 
00190 #endif
00191 
00192 void cc3000::usync_callback(int32_t event_type, uint8_t *data, uint8_t length) {
00193     if (event_type == HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE) {
00194         DBG_CC("Callback : HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE");
00195         _status.smart_config_complete = 1;
00196         _status.stop_smart_config = 1;
00197     }
00198 
00199     if (event_type == HCI_EVNT_WLAN_UNSOL_CONNECT) {
00200         DBG_CC("Callback : HCI_EVNT_WLAN_UNSOL_CONNECT");
00201         _status.connected = 1;
00202         // Connect message is always followed by a DHCP message, connection is not useable until then
00203         _status.dhcp      = 0;
00204     }
00205 
00206     if (event_type == HCI_EVNT_WLAN_UNSOL_DISCONNECT) {
00207         DBG_CC("Callback : HCI_EVNT_WLAN_UNSOL_DISCONNECT");
00208         _status.connected = 0;
00209         _status.dhcp      = 0;
00210         _status.dhcp_configured = 0;
00211     }
00212 
00213     if (event_type == HCI_EVNT_WLAN_UNSOL_DHCP) {
00214 #if (CC3000_ETH_COMPAT == 1)
00215         _socket.inet_ntoa_r ( htonl(*((uint32_t *)(&data[NETAPP_IPCONFIG_IP_OFFSET]))), ip_addr, 17);
00216         _socket.inet_ntoa_r ( htonl(*((uint32_t *)(&data[NETAPP_IPCONFIG_GW_OFFSET]))), gateway, 17);
00217         _socket.inet_ntoa_r ( htonl(*((uint32_t *)(&data[NETAPP_IPCONFIG_SUBNET_OFFSET]))), networkmask, 17);
00218         _socket.inet_ntoa_r ( htonl(*((uint32_t *)(&data[NETAPP_IPCONFIG_MAC_OFFSET]))), mac_addr, 19);
00219 #endif
00220         if (*(data + NETAPP_IPCONFIG_MAC_OFFSET) == 0) {
00221             _status.dhcp = 1;
00222             DBG_CC("Callback : HCI_EVNT_WLAN_UNSOL_DHCP %i.%i.%i.%i", data[3], data[2], data[1], data[0]);
00223         } else {
00224             DBG_CC("Callback : HCI_EVNT_WLAN_UNSOL_DHCP - Disconnecting");
00225             _status.dhcp = 0;
00226         }
00227     }
00228 
00229     if (event_type == HCI_EVENT_CC3000_CAN_SHUT_DOWN) {
00230         // Note this means the modules is idle, so it could be shutdown..
00231         //DBG_CC("Callback : HCI_EVENT_CC3000_CAN_SHUT_DOWN");
00232         _status.ok_to_shut_down = 1;
00233     }
00234 
00235     if (event_type == HCI_EVNT_WLAN_ASYNC_PING_REPORT) {
00236         DBG_CC("Callback : HCI_EVNT_WLAN_ASYNC_PING_REPORT");
00237         memcpy(&_ping_report, data, length);
00238     }
00239 
00240     if (event_type == HCI_EVNT_BSD_TCP_CLOSE_WAIT) {
00241         uint8_t socketnum = data[0];
00242         DBG_CC("Callback : HCI_EVNT_BSD_TCP_CLOSE_WAIT - Socket : %d", socketnum);
00243         if (socketnum < MAX_SOCKETS) {
00244             _closed_sockets[socketnum] = true; /* clients socket is closed */
00245         }
00246     }
00247 }
00248 
00249 void cc3000::start_smart_config(const uint8_t *smart_config_key) {
00250     _status.smart_config_complete = 0;
00251     _wlan.ioctl_set_connection_policy(0, 0, 0);
00252 
00253     if (_status.connected == 1) {
00254         disconnect();
00255     }
00256 
00257     //Wait until CC3000 is disconected
00258     while (_status.connected == 1) {
00259         wait_us(5);
00260         _event.hci_unsolicited_event_handler();
00261     }
00262 
00263     // Trigger the Smart Config process
00264     _wlan.smart_config_set_prefix(cc3000_prefix);
00265     // Start the Smart Config process with AES disabled
00266     _wlan.smart_config_start(0);
00267 
00268     DBG_CC("Waiting for smartconfig to be completed");
00269 
00270     // Wait for Smart config finished
00271     while (_status.smart_config_complete == 0) {
00272         wait_ms(100);
00273     }
00274 
00275     DBG_CC("Smartconfig finished");
00276 
00277 #ifndef CC3000_UNENCRYPTED_SMART_CONFIG
00278     // create new entry for AES encryption key
00279     _nvmem.create_entry(NVMEM_AES128_KEY_FILEID, 16);
00280     // write AES key to NVMEM
00281     _security.aes_write_key((uint8_t *)(&smart_config_key[0]));
00282     // Decrypt configuration information and add profile
00283     _wlan.smart_config_process();
00284 #endif
00285 
00286     // Configure to connect automatically to the AP retrieved in the
00287     // Smart config process
00288     _wlan.ioctl_set_connection_policy(0, 0, 1);
00289 
00290     // reset the CC3000
00291     _wlan.stop();
00292     _status.enabled = 0;
00293     wait(5);
00294     _wlan.start(0);
00295     _status.enabled = 1;
00296 
00297     // Mask out all non-required events
00298     _wlan.set_event_mask(HCI_EVNT_WLAN_KEEPALIVE | HCI_EVNT_WLAN_UNSOL_INIT);
00299 }
00300 
00301 bool cc3000::connect_secure(const uint8_t *ssid, const uint8_t *key, int32_t security_mode) {
00302 #ifdef CC3000_TINY_DRIVER
00303     return false; /* not supported*/
00304 #else
00305     uint32_t ret;
00306 
00307     //_wlan.disconnect();
00308     wait_ms(3);
00309     ret = _wlan.connect(security_mode, ssid, strlen((const char *)ssid), 0, (uint8_t *)key, strlen((const char *)key));
00310     if (ret == 0) { /* TODO static internal cc3000 state 0 to TRUE */
00311       ret = true;
00312     } else {
00313       ret = false;
00314     }
00315     return ret;
00316 #endif
00317 }
00318 
00319 bool cc3000::connect_non_blocking(const uint8_t *ssid, const uint8_t *key, int32_t security_mode)
00320 {
00321     bool ret = false;
00322 
00323     if (key == 0) {
00324         if (connect_open(ssid)) {
00325             ret = true;
00326         }
00327     } else {
00328     #ifndef CC3000_TINY_DRIVER
00329         if (connect_secure(ssid,key,security_mode)) {
00330             ret = true;
00331         }
00332     #else
00333         /* secure connection not supported with TINY_DRIVER */
00334     #endif
00335     }
00336 
00337     return ret;
00338 }
00339 
00340 bool cc3000::connect_to_AP(const uint8_t *ssid, const uint8_t *key, int32_t security_mode) {
00341     Timer t;
00342     bool ret = true;
00343 
00344     t.start();
00345     while (is_connected() == false) {
00346         if (key == 0) {
00347             if (connect_open(ssid)) {
00348                 break;
00349             }
00350         } else {
00351 #ifndef CC3000_TINY_DRIVER
00352             if (connect_secure(ssid,key,security_mode)) {
00353                 break;
00354             }
00355 #else
00356             return false; /* secure connection not supported with TINY_DRIVER */
00357 #endif
00358         }
00359 
00360         /* timeout 10 seconds */
00361         if (t.read_ms() > 10000) {
00362             ret = false;
00363             DBG_CC("Connection to AP failed");
00364             break;
00365         }
00366     }
00367 
00368     return ret;
00369 }
00370 
00371 void cc3000::start(uint8_t patch) {
00372     _wlan.start(patch);
00373     _status.enabled = 1;
00374     _wlan.set_event_mask(HCI_EVNT_WLAN_UNSOL_INIT | HCI_EVNT_WLAN_KEEPALIVE);
00375 }
00376 
00377 void cc3000::stop(void) {
00378     _wlan.stop();
00379     _status.enabled = 0;
00380 }
00381 
00382 void cc3000::restart(uint8_t patch) {
00383     _wlan.stop();
00384     _status.enabled = 0;
00385     wait_ms(500);
00386     _wlan.start(patch);
00387     _status.enabled = 1;
00388 }
00389 
00390 bool cc3000::connect_open(const uint8_t *ssid) {
00391     _wlan.disconnect();
00392     wait_ms(3);
00393     uint32_t ret;
00394 #ifndef CC3000_TINY_DRIVER
00395     ret = _wlan.connect(0,ssid, strlen((const char *)ssid), 0, 0, 0);
00396 #else
00397     ret = _wlan.connect(ssid, strlen((const char *)ssid));
00398 #endif
00399     if (ret == 0) {
00400         ret = true;
00401     } else {
00402         ret = false;
00403     }
00404     return ret;
00405 }
00406 
00407 bool cc3000::is_enabled()
00408 {
00409     return _status.enabled;
00410 }
00411 
00412 bool cc3000::is_connected() {
00413     if (( _status.connected ) && ( _status.dhcp )) {
00414         return 1;
00415     } else {
00416         return 0;
00417     }
00418 }
00419 
00420 bool cc3000::is_dhcp_configured() {
00421     return _status.dhcp;
00422 }
00423 
00424 bool cc3000::is_smart_confing_completed() {
00425     return _status.smart_config_complete;
00426 }
00427 
00428 uint8_t cc3000::get_mac_address(uint8_t address[6]) {
00429     return _nvmem.get_mac_address(address);
00430 }
00431 
00432 uint8_t cc3000::set_mac_address(uint8_t address[6]) {
00433     return _nvmem.set_mac_address(address);
00434 }
00435 
00436 void cc3000::get_user_file_info(uint8_t *info_file, size_t size) {
00437     _nvmem.read( NVMEM_USER_FILE_1_FILEID, size, 0, info_file);
00438 }
00439 
00440 uint8_t cc3000::read_sp_version(uint8_t firmware[2]){
00441     return _nvmem.read_sp_version(firmware);
00442     }
00443 
00444 uint8_t  cc3000::write_patch(uint32_t file_id, uint32_t length, const uint8_t *data){
00445       if(file_id == NVMEM_WLAN_DRIVER_SP_FILEID || file_id == NVMEM_WLAN_FW_SP_FILEID){
00446             return _nvmem.write_patch(file_id, length, data);
00447         }
00448         else return (1);  // error
00449 }
00450 
00451 #ifndef CC3000_TINY_DRIVER
00452 bool cc3000::get_ip_config(tNetappIpconfigRetArgs *ip_config) {
00453     if ((_status.dhcp == false) || (_status.connected == false)) {
00454         return false;
00455     }
00456 
00457     _netapp.ipconfig(ip_config);
00458     return true;
00459 }
00460 #endif
00461 
00462 void cc3000::delete_profiles(void) {
00463     _wlan.ioctl_set_connection_policy(0, 0, 0);
00464     _wlan.ioctl_del_profile(255);
00465 
00466     tUserFS user_info;
00467     get_user_file_info((uint8_t *)&user_info, sizeof(user_info));
00468     user_info.FTC = 0;
00469     set_user_file_info((uint8_t *)&user_info, sizeof(user_info));
00470 }
00471 
00472 void cc3000::set_user_file_info(uint8_t *info_file, size_t size) {
00473     _nvmem.write( NVMEM_USER_FILE_1_FILEID, size, 0, info_file);
00474 }
00475 
00476 uint32_t cc3000::ping(uint32_t ip, uint8_t attempts, uint16_t timeout, uint8_t size) {
00477 #ifndef CC3000_TINY_DRIVER
00478     uint32_t reversed_ip = (ip >> 24) | ((ip >> 8) & 0xFF00) | ((ip << 8) & 0xFF0000) | (ip << 24);
00479 
00480     _ping_report.packets_received = 0;
00481     if (_netapp.ping_send(&reversed_ip, attempts, size, timeout) == -1) {
00482         DBG_CC("Failed to send ping");
00483         return 0;
00484     }
00485     wait_ms(timeout*attempts*2);
00486 
00487     /* known issue of cc3000 - sent number is send + received */
00488     // TODO : Remove the Sent/recv'd counts until ti fix the firmware issue?
00489     DBG_CC("Sent: %d",_ping_report.packets_sent);
00490     DBG_CC("Received: %d",_ping_report.packets_received);
00491     DBG_CC("Min time: %d",_ping_report.min_round_time);
00492     DBG_CC("Max time: %d",_ping_report.max_round_time);
00493     DBG_CC("Avg time: %d",_ping_report.avg_round_time);
00494 
00495     return _ping_report.packets_received;
00496 #else
00497     return 0;
00498 #endif
00499 }
00500 
00501 /* Conversion between uint types and C strings */
00502 uint8_t* UINT32_TO_STREAM_f (uint8_t *p, uint32_t u32)
00503 {
00504     *(p)++ = (uint8_t)(u32);
00505     *(p)++ = (uint8_t)((u32) >> 8);
00506     *(p)++ = (uint8_t)((u32) >> 16);
00507     *(p)++ = (uint8_t)((u32) >> 24);
00508     return p;
00509 }
00510 
00511 
00512 uint8_t* UINT16_TO_STREAM_f (uint8_t *p, uint16_t u16)
00513 {
00514     *(p)++ = (uint8_t)(u16);
00515     *(p)++ = (uint8_t)((u16) >> 8);
00516     return p;
00517 }
00518 
00519 
00520 uint16_t STREAM_TO_UINT16_f(uint8_t *p, uint16_t offset)
00521 {
00522     return (uint16_t)((uint16_t)((uint16_t)
00523            (*(p + offset + 1)) << 8) + (uint16_t)(*(p + offset)));
00524 }
00525 
00526 
00527 uint32_t STREAM_TO_UINT32_f(uint8_t *p, uint16_t offset)
00528 {
00529     return (uint32_t)((uint32_t)((uint32_t)
00530            (*(p + offset + 3)) << 24) + (uint32_t)((uint32_t)
00531            (*(p + offset + 2)) << 16) + (uint32_t)((uint32_t)
00532            (*(p + offset + 1)) << 8) + (uint32_t)(*(p + offset)));
00533 }
00534 
00535 } // mbed_cc3000 namespace
00536