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.
Dependencies: MaximInterface mbed
ESP8266.cpp
- Committer:
- IanBenzMaxim
- Date:
- 2016-08-15
- Revision:
- 19:b8b0cd35f7b4
- Parent:
- 9:bc3d211d75ce
- Child:
- 20:cdba71cb5506
File content as of revision 19:b8b0cd35f7b4:
/*******************************************************************************
* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Maxim Integrated
* Products, Inc. shall not be used except as stated in the Maxim Integrated
* Products, Inc. Branding Policy.
*
* The mere transfer of this software does not imply any licenses
* of trade secrets, proprietary technology, copyrights, patents,
* trademarks, maskwork rights, or any other form of intellectual
* property whatsoever. Maxim Integrated Products, Inc. retains all
* ownership rights.
*******************************************************************************
*/
#include <cstdlib>
#include "ESP8266.hpp"
#include "Timer.h"
#include "wait_api.h"
ESP8266* ESP8266::defaultInstance = NULL;
static inline void disableRecvData()
{
__disable_irq();
}
static inline void enableRecvData()
{
__enable_irq();
}
void ESP8266::setDefaultInstance(ESP8266 * const instance)
{
if (instance != NULL)
defaultInstance = instance;
}
ESP8266** ESP8266::getDefaultInstance()
{
return &defaultInstance;
}
ESP8266::ESP8266(const PinName tx, const PinName rx, const PinName rst, const PinName CH_PD, const int baud, mbed::Serial * debugMsgIntf)
: AT_intf(tx, rx), resetPin(rst), powerDownPin(CH_PD), debugMsg(debugMsgIntf), parseRecvReset(false)
{
AT_intf.baud(baud);
AT_intf.attach(this, &ESP8266::recv_AT_data_cb);
// Ensure that device is not held in reset
if (resetPin.is_connected())
resetPin = 1;
// Power down device at startup due to high current demand
setPowered(false);
if (defaultInstance == NULL)
defaultInstance = this;
}
ESP8266::~ESP8266()
{
if (defaultInstance == this)
defaultInstance = NULL;
}
void ESP8266::reset()
{
if (resetPin.is_connected())
{
resetPin = 0;
wait_ms(100);
resetPin = 1;
wait_ms(1000);
}
}
bool ESP8266::powered() const
{
bool isPowered;
if (powerDownPin.is_connected())
{
isPowered = powerDownPin.read();
}
else
{
isPowered = false;
}
return isPowered;
}
void ESP8266::setPowered(bool powered)
{
if (powerDownPin.is_connected())
powerDownPin = powered;
}
ESP8266::CmdResult ESP8266::performSelfTest()
{
return sendCommand(CmdBuilder(""));
}
ESP8266::CmdResult ESP8266::setCurrentWifiMode(const ESP8266::WifiMode mode)
{
CmdBuilder builder("CWMODE_CUR");
builder.addRawArgument(mode);
return sendCommand(builder);
}
ESP8266::CmdResult ESP8266::joinCurrentAccessPoint(const std::string & ssid, const std::string & pwd, const std::string & bssid)
{
CmdBuilder builder("CWJAP_CUR");
builder.addStringArgument(ssid);
builder.addStringArgument(pwd);
if (bssid != "")
builder.addStringArgument(bssid);
return sendCommand(builder);
}
ESP8266::CmdResult ESP8266::quitAccessPoint()
{
return sendCommand(CmdBuilder("CWQAP"));
}
ESP8266::CmdResult ESP8266::setMaxRFTXPower(const float power_dBm)
{
int power_arg = (int)(power_dBm * 4);
if (power_arg > 82)
power_arg = 82;
else if (power_arg < 0)
power_arg = 0;
CmdBuilder builder("RFPOWER");
builder.addRawArgument(power_arg);
return sendCommand(builder);
}
ESP8266::CmdResult ESP8266::ping(const std::string & IP)
{
CmdBuilder builder("PING");
builder.addStringArgument(IP);
return sendCommand(builder);
}
ESP8266::CmdResult ESP8266::openConnection(const ESP8266::ConnType type, const std::string & remoteIP, const unsigned int remotePort)
{
CmdBuilder builder("CIPSTART");
builder.addStringArgument((type == TCP) ? "TCP" : "UDP");
builder.addStringArgument(remoteIP);
builder.addRawArgument(remotePort);
return sendCommand(builder);
}
ESP8266::CmdResult ESP8266::closeConnection()
{
return sendCommand(CmdBuilder("CIPCLOSE"));
}
ESP8266::CmdResult ESP8266::sendData(const std::string & data)
{
CmdBuilder builder("CIPSEND");
builder.addRawArgument(data.length());
ESP8266::CmdResult result = sendCommand(builder);
if (result == ESP8266::AT_OK)
result = send_AT_data(data, false);
return result;
}
ESP8266::CmdResult ESP8266::sendCommand(const CmdBuilder & cmd)
{
return send_AT_data(cmd.str(), true);
}
bool ESP8266::recvIpDataReadable()
{
bool result;
disableRecvData(); // Lock queue access
result = !recvIpDataBuffer.empty();
enableRecvData(); // Unlock queue access
return result;
}
char ESP8266::getcRecvIpData()
{
char received;
disableRecvData(); // Lock queue access
// Pop next char or set to NTC if not data in buffer
if (!recvIpDataBuffer.pop(received))
received = '\0';
enableRecvData(); // Unlock queue access
return received;
}
void ESP8266::clearRecvData()
{
disableRecvData(); // Lock queue access
recvIpDataBuffer.reset();
parseRecvReset = true;
enableRecvData(); // Unlock queue access
}
ESP8266::CmdResult ESP8266::send_AT_data(const std::string & cmdString, const bool expectEcho)
{
const int timeout_ms = 10000;
mbed::Timer timer;
ESP8266::CmdResult result = ESP8266::HardwareError;
std::string response;
disableRecvData(); // Lock for manual data handling in this procedure
// Flush receive buffer
while (AT_intf.readable())
AT_intf.getc();
// Begin counting for timeout
timer.start();
for (size_t i = 0; i < cmdString.length(); i++)
{
// Write next character
while (!AT_intf.writeable())
{
if (timer.read_ms() > timeout_ms)
{
result = TimeoutError;
goto exit;
}
}
AT_intf.putc(cmdString[i]);
// Wait for echo
if (expectEcho && (cmdString[i] != '\r') && (cmdString[i] != '\n'))
{
while (!AT_intf.readable())
{
if (timer.read_ms() > timeout_ms)
{
result = TimeoutError;
goto exit;
}
}
// Compare to written character
if (AT_intf.getc() != cmdString[i])
{
// Handle error
result = ESP8266::HardwareError;
goto exit;
}
}
}
while (result == ESP8266::HardwareError)
{
// Wait to receive something
response.clear();
while (!read_line(response)) ;
// Check if valid response
if (response == "OK")
result = ESP8266::AT_OK;
else if (response == "FAIL")
result = ESP8266::AT_FAIL;
else if (response == "ERROR")
result = ESP8266::AT_ERROR;
else if (response == "SEND OK") // Used by AT+CIPSEND
result = ESP8266::AT_OK;
else if (response == "ALREADY CONNECT") // Used by AT+CIPSTART
result = ESP8266::AT_OK;
if (timer.read_ms() > timeout_ms)
{
result = TimeoutError;
break;
}
}
exit:
enableRecvData(); // Enable interrupt processing
return result;
}
bool ESP8266::read_line(std::string & line)
{
char received;
while (AT_intf.readable())
{
received = AT_intf.getc();
if (received == '\n')
{
return true;
}
else if (received != '\r')
{
line.push_back(received);
}
}
return false;
}
void ESP8266::recv_AT_data_cb()
{
while (AT_intf.readable())
{
char received = AT_intf.getc();
parseRecvIpData(received);
parseRecvConnClosedMsg(received);
parseRecvReset = false;
}
}
void ESP8266::parseRecvIpData(const char received)
{
enum DataRecvState
{
Header,
Length,
Data,
Reset
};
static const char findChars[] = "+IPD,";
static const size_t maxSizeDigits = 4;
static size_t dataFinishedSize = 0;
static int index = 0;
static char sizeDigits[] = { '\0', '\0', '\0', '\0', '\0' };
static DataRecvState state = Header;
if (parseRecvReset)
state = Reset;
switch (state)
{
case Reset:
default:
index = 0;
dataFinishedSize = 0;
state = Header;
// Continue processing switch
case Header:
if (received == findChars[index])
{
if (findChars[++index] == '\0')
{
index = 0;
state = Length;
}
}
else
{
state = Reset;
}
break;
case Length:
if ((received <= '9') && (received >= '0'))
{
if (index < maxSizeDigits)
{
sizeDigits[index++] = received;
}
else
{
state = Reset;
}
}
else if (received == ':')
{
dataFinishedSize = std::atoi(sizeDigits);
if (dataFinishedSize == 0)
{
state = Reset;
}
else
{
index = 0;
state = Data;
}
}
else
{
state = Reset;
}
break;
case Data:
if (index < dataFinishedSize)
{
recvIpDataBuffer.push(received);
index++;
}
else
{
state = Reset;
}
break;
};
}
void ESP8266::parseRecvConnClosedMsg(const char received)
{
static const char findChars[] = "CLOSED";
static int index = 0;
bool shouldReset = parseRecvReset;
if (received == findChars[index])
{
if (findChars[++index] == '\0')
{
printDbgMsg(findChars);
shouldReset = true;
}
}
else
{
shouldReset = true;
}
if (shouldReset)
{
index = 0;
}
}
void ESP8266::printDbgMsg(const char * message)
{
if (debugMsg != NULL)
debugMsg->printf("%s", message);
}
ESP8266::CmdBuilder::CmdBuilder(const std::string & cmd)
{
clear(cmd);
}
void ESP8266::CmdBuilder::clear(const std::string & cmd)
{
numArgs = 0;
cmdStream.str("");
cmdStream << "AT";
if (cmd != "")
cmdStream << "+" << cmd;
}
void ESP8266::CmdBuilder::addStringArgument(const std::string & arg)
{
std::ostringstream argStream;
argStream << "\"" << arg << "\"";
addRawArgument<std::string>(argStream.str());
}
std::string ESP8266::CmdBuilder::str() const
{
std::string cmdString = cmdStream.str();
cmdString.append("\r\n");
return cmdString;
}
MAXREFDES143#: DeepCover Embedded Security in IoT Authenticated Sensing & Notification