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 SPWF01SA by
SPWFSA01.cpp
- Committer:
- mridup
- Date:
- 2016-08-19
- Revision:
- 14:868b0fd4e84a
- Parent:
- 13:f21e4e73bbb6
- Child:
- 15:e56c9e744ab6
File content as of revision 14:868b0fd4e84a:
/* SPWFInterface Example
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SPWFSA01.h"
#include "mbed_debug.h"
#define SPWFSA01_CONNECT_TIMEOUT 15000
#define SPWFSA01_SEND_TIMEOUT 500
#define SPWFSA01_RECV_TIMEOUT 1500//some commands like AT&F/W takes some time to get the result back!
#define SPWFSA01_MISC_TIMEOUT 500
SPWFSA01::SPWFSA01(PinName tx, PinName rx, bool debug)
: _serial(tx, rx, 1024), _parser(_serial),
_wakeup(D14, PIN_INPUT, PullNone, 0), _reset(D15, PIN_INPUT, PullNone, 1),
//PC_12->D15, PC_8->D14 (re-wires needed in-case used, currently not used)
dbg_on(debug)
//Pin PC_8 is wakeup pin
//Pin PA_12 is reset pin
{
_serial.baud(115200);
_reset.output();
_wakeup.output();
_parser.debugOn(debug);
}
bool SPWFSA01::startup(int mode)
{
setTimeout(SPWFSA01_RECV_TIMEOUT);
/*Test module before reset*/
waitSPWFReady();
/*Reset module*/
reset();
/*set local echo to 0*/
if(!(_parser.send("AT+S.SCFG=localecho1,%d\r", 0) && _parser.recv("OK")))
{
debug_if(dbg_on, "SPWF> error local echo set\r\n");
return false;
}
/*reset factory settings*/
if(!(_parser.send("AT&F") && _parser.recv("OK")))
{
debug_if(dbg_on, "SPWF> error AT&F\r\n");
return false;
}
/*set idle mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/
if(!(_parser.send("AT+S.SCFG=wifi_mode,%d\r", mode) && _parser.recv("OK")))
{
debug_if(dbg_on, "SPWF> error wifi mode set\r\n");
return false;
}
/* save current setting in flash */
if(!(_parser.send("AT&W") && _parser.recv("OK")))
{
debug_if(dbg_on, "SPWF> error AT&W\r\n");
return false;
}
/*reset again and send AT command and check for result (AT->OK)*/
reset();
return true;
}
bool SPWFSA01::hw_reset(void)
{
/* reset the pin PC12 */
_reset.write(0);
wait_ms(200);
_reset.write(1);
wait_ms(100);
return 1;
}
bool SPWFSA01::reset(void)
{
if(!_parser.send("AT+CFUN=1")) return false;
while(1) {
if (_parser.recv("+WIND:32:WiFi Hardware Started\r")) {
return true;
}
}
}
void SPWFSA01::waitSPWFReady(void)
{
//wait_ms(200);
while(1)
if(_parser.send("AT") && _parser.recv("OK"))
//till we get OK from AT command
//printf("\r\nwaiting for reset to complete..\n");
return;
}
/* Security Mode
None = 0,
WEP = 1,
WPA_Personal = 2,
*/
bool SPWFSA01::connect(const char *ap, const char *passPhrase, int securityMode)
{
uint32_t n1, n2, n3, n4;
//AT+S.SCFG=wifi_wpa_psk_text,%s\r
if(!(_parser.send("AT+S.SCFG=wifi_wpa_psk_text,%s", passPhrase) && _parser.recv("OK")))
{
debug_if(dbg_on, "SPWF> error pass set\r\n");
return false;
}
//AT+S.SSIDTXT=%s\r
if(!(_parser.send("AT+S.SSIDTXT=%s", ap) && _parser.recv("OK")))
{
debug_if(dbg_on, "SPWF> error ssid set\r\n");
return false;
}
//AT+S.SCFG=wifi_priv_mode,%d\r
if(!(_parser.send("AT+S.SCFG=wifi_priv_mode,%d", securityMode) && _parser.recv("OK")))
{
debug_if(dbg_on, "SPWF> error security mode set\r\n");
return false;
}
//"AT+S.SCFG=wifi_mode,%d\r"
/*set idle mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/
if(!(_parser.send("AT+S.SCFG=wifi_mode,%d\r", 1) && _parser.recv("OK")))
{
debug_if(dbg_on, "SPWF> error wifi mode set\r\n");
return false;
}
//AT&W
/* save current setting in flash */
if(!(_parser.send("AT&W") && _parser.recv("OK")))
{
debug_if(dbg_on, "SPWF> error AT&W\r\n");
return false;
}
//reset module
reset();
while(1)
if((_parser.recv("+WIND:24:WiFi Up:%u.%u.%u.%u\r",&n1, &n2, &n3, &n4)))
{
break;
}
return true;
}
bool SPWFSA01::disconnect(void)
{
//"AT+S.SCFG=wifi_mode,%d\r"
/*set idle mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/
if(!(_parser.send("AT+S.SCFG=wifi_mode,%d\r", 0) && _parser.recv("OK")))
{
debug_if(dbg_on, "SPWF> error wifi mode set\r\n");
return false;
}
//AT&W
/* save current setting in flash */
if(!(_parser.send("AT&W") && _parser.recv("OK")))
{
debug_if(dbg_on, "SPWF> error AT&W\r\n");
return false;
}
//reset module
reset();
return true;
}
bool SPWFSA01::dhcp(int mode)
{
//only 3 valid modes
//0->off(ip_addr must be set by user), 1->on(auto set by AP), 2->on&customize(miniAP ip_addr can be set by user)
if(mode < 0 || mode > 2) {
return false;
}
return _parser.send("AT+S.SCFG=ip_use_dhcp,%d\r", mode)
&& _parser.recv("OK");
}
const char *SPWFSA01::getIPAddress(void)
{
uint32_t n1, n2, n3, n4;
if (!(_parser.send("AT+S.STS=ip_ipaddr")
&& _parser.recv("# ip_ipaddr = %u.%u.%u.%u", &n1, &n2, &n3, &n4)
&& _parser.recv("OK"))) {
debug_if(dbg_on, "SPWF> getIPAddress error\r\n");
return 0;
}
sprintf((char*)_ip_buffer,"%u.%u.%u.%u", n1, n2, n3, n4);
return _ip_buffer;
}
const char *SPWFSA01::getMACAddress(void)
{
uint32_t n1, n2, n3, n4, n5, n6;
if (!(_parser.send("AT+S.GCFG=nv_wifi_macaddr")
&& _parser.recv("# nv_wifi_macaddr = %x:%x:%x:%x:%x:%x", &n1, &n2, &n3, &n4, &n5, &n6)
&& _parser.recv("OK"))) {
debug_if(dbg_on, "SPWF> getMACAddress error\r\n");
return 0;
}
sprintf((char*)_mac_buffer,"%02X:%02X:%02X:%02X:%02X:%02X", n1, n2, n3, n4, n5, n6);
return _mac_buffer;
}
bool SPWFSA01::isConnected(void)
{
return getIPAddress() != 0;
}
bool SPWFSA01::open(const char *type, int* id, const char* addr, int port)
{
Timer timer;
timer.start();
if(!_parser.send("AT+S.SOCKON=%s,%d,%s,ind", addr, port, type))
{
debug_if(dbg_on, "SPWF> error opening socket\r\n");
return false;
}
while(1)
{
if( _parser.recv(" ID: %d", id)
&& _parser.recv("OK"))
break;
if (timer.read_ms() > SPWFSA01_CONNECT_TIMEOUT) {
return false;
}
//TODO:implement time-out functionality in case of no response
//if(timeout) return false;
//TODO: deal with errors like "ERROR: Failed to resolve name"
//TODO: deal with errors like "ERROR: Data mode not available"
}
return true;
}
bool SPWFSA01::send(int id, const void *data, uint32_t amount)
{
char _buf[18];
setTimeout(SPWFSA01_SEND_TIMEOUT);
sprintf((char*)_buf,"AT+S.SOCKW=%d,%d\r", id, amount);
//May take a second try if device is busy
for (unsigned i = 0; i < 2; i++) {
if (_parser.write((char*)_buf, strlen(_buf)) >=0
&& _parser.write((char*)data, (int)amount) >= 0
&& _parser.recv("OK")) {
return true;
}
}
return false;
}
int32_t SPWFSA01::recv(int id, void *data, uint32_t amount)
{
uint32_t recv_amount, read_amt;
int recv_id;
char _buf[18];
if (!(_parser.recv("+WIND:55:Pending Data:%d:%u", &recv_id, &recv_amount)
&& recv_id == id
//&& _parser.send("AT+S.SOCKQ=%d", id)//send a query (will be required for secure sockets)
//&& _parser.recv(" DATALEN: %u", &recv_amount)
//&& _parser.recv("OK")
&& recv_amount <= amount)) {
return -1;//Block call
}
//&& sprintf((char*)_buf,"AT+S.SOCKR=%d,%d\r", id, recv_amount)
//&& _parser.write((char*)_buf, strlen(_buf))
if (!_parser.send("AT+S.SOCKR=%d,%d", id, recv_amount)) {
//if error, resend SOCKR again to flush the socket
//This should prevent Error: Pending Data errors or the next WIND showing this pending data
sprintf((char*)_buf,"AT+S.SOCKR=%d,%d\r", id, recv_amount);
_parser.write((char*)_buf, strlen(_buf));
debug_if(dbg_on, "SPWF> read send SOCKR error\r\n");
return -2;//return NSAPI_ERROR_DEVICE_ERROR
}
read_amt = _parser.read((char*)data, recv_amount);
if (read_amt<=0) {
debug_if(dbg_on, "SPWF> read recv SOCKR error: read_amt = %d\r\n", read_amt);
return -2;//return NSAPI_ERROR_DEVICE_ERROR
}
//Sometimes OK is not received because _parser.read() reads in ERROR statement. "E.g. ERROR: Command not found".
//ERROR statement hence takes up space in recv_amount and hence OK is not read as a result.
if (!_parser.recv("OK")) {
debug_if(dbg_on, "SPWF> read recv SOCKR OK error\r\n");
if(std::strncmp("\r\nERROR: ", (const char* )data, 9)==0) {
debug_if(dbg_on, "SPWF> Module Error Reply\r\n");
return -2;
}
/*int i = 0;
char * buf = (char*)data;
for ( ; i < recv_amount; i++) {
debug_if(dbg_on, ("%d = %c\r\n", i, buf[i]);
}*/
return -2;//return NSAPI_ERROR_DEVICE_ERROR
}
return recv_amount;
}
bool SPWFSA01::close(int id)
{
//May take a second try if device is busy or error is returned
for (unsigned i = 0; i < 2; i++) {
if (_parser.send("AT+S.SOCKC=%d", id)
&& _parser.recv("OK")) {
return true;
}
else
{
if(_parser.recv("ERROR: Pending data"))
debug_if(dbg_on, "SPWF> ERROR!!!!\r\n");
return false;
}
//TODO: Deal with "ERROR: Pending data" (Closing a socket with pending data)
}
return false;
}
void SPWFSA01::setTimeout(uint32_t timeout_ms)
{
_parser.setTimeout(timeout_ms);
}
bool SPWFSA01::readable()
{
return _serial.readable();
}
bool SPWFSA01::writeable()
{
return _serial.writeable();
}
