Martin Kojtal / cc3000_hostdriver_mbedsocket Featured

Dependents:   cc3000_hello_world_demo cc3000_simple_socket_demo cc3000_ntp_demo cc3000_ping_demo ... more

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