mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #23 from geky/esp8266
Added ESP8266Interface
commit
1fab13ea09
|
@ -0,0 +1,309 @@
|
|||
/* 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.
|
||||
*
|
||||
* @section DESCRIPTION
|
||||
*
|
||||
* Parser for the AT command syntax
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ATParser.h"
|
||||
#include "mbed_debug.h"
|
||||
|
||||
|
||||
// getc/putc handling with timeouts
|
||||
int ATParser::putc(char c)
|
||||
{
|
||||
Timer timer;
|
||||
timer.start();
|
||||
|
||||
while (true) {
|
||||
if (_serial->writeable()) {
|
||||
return _serial->putc(c);
|
||||
}
|
||||
if (timer.read_ms() > _timeout) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ATParser::getc()
|
||||
{
|
||||
Timer timer;
|
||||
timer.start();
|
||||
|
||||
while (true) {
|
||||
if (_serial->readable()) {
|
||||
return _serial->getc();
|
||||
}
|
||||
if (timer.read_ms() > _timeout) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ATParser::flush()
|
||||
{
|
||||
while (_serial->readable()) {
|
||||
_serial->getc();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// read/write handling with timeouts
|
||||
int ATParser::write(const char *data, int size)
|
||||
{
|
||||
int i = 0;
|
||||
for ( ; i < size; i++) {
|
||||
if (putc(data[i]) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int ATParser::read(char *data, int size)
|
||||
{
|
||||
int i = 0;
|
||||
for ( ; i < size; i++) {
|
||||
int c = getc();
|
||||
if (c < 0) {
|
||||
return -1;
|
||||
}
|
||||
data[i] = c;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
// printf/scanf handling
|
||||
int ATParser::vprintf(const char *format, va_list args)
|
||||
{
|
||||
if (vsprintf(_buffer, format, args) < 0) {
|
||||
return false;
|
||||
}
|
||||
int i = 0;
|
||||
for ( ; _buffer[i]; i++) {
|
||||
if (putc(_buffer[i]) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int ATParser::vscanf(const char *format, va_list args)
|
||||
{
|
||||
// Since format is const, we need to copy it into our buffer to
|
||||
// add the line's null terminator and clobber value-matches with asterisks.
|
||||
//
|
||||
// We just use the beginning of the buffer to avoid unnecessary allocations.
|
||||
int i = 0;
|
||||
int offset = 0;
|
||||
|
||||
while (format[i]) {
|
||||
if (format[i] == '%' && format[i+1] != '%' && format[i+1] != '*') {
|
||||
_buffer[offset++] = '%';
|
||||
_buffer[offset++] = '*';
|
||||
i++;
|
||||
} else {
|
||||
_buffer[offset++] = format[i++];
|
||||
}
|
||||
}
|
||||
|
||||
// Scanf has very poor support for catching errors
|
||||
// fortunately, we can abuse the %n specifier to determine
|
||||
// if the entire string was matched.
|
||||
_buffer[offset++] = '%';
|
||||
_buffer[offset++] = 'n';
|
||||
_buffer[offset++] = 0;
|
||||
|
||||
// To workaround scanf's lack of error reporting, we actually
|
||||
// make two passes. One checks the validity with the modified
|
||||
// format string that only stores the matched characters (%n).
|
||||
// The other reads in the actual matched values.
|
||||
//
|
||||
// We keep trying the match until we succeed or some other error
|
||||
// derails us.
|
||||
int j = 0;
|
||||
|
||||
while (true) {
|
||||
// Ran out of space
|
||||
if (j+1 >= _buffer_size - offset) {
|
||||
return false;
|
||||
}
|
||||
// Recieve next character
|
||||
int c = getc();
|
||||
if (c < 0) {
|
||||
return -1;
|
||||
}
|
||||
_buffer[offset + j++] = c;
|
||||
_buffer[offset + j] = 0;
|
||||
|
||||
// Check for match
|
||||
int count = -1;
|
||||
sscanf(_buffer+offset, _buffer, &count);
|
||||
|
||||
// We only succeed if all characters in the response are matched
|
||||
if (count == j) {
|
||||
// Store the found results
|
||||
vsscanf(_buffer+offset, format, args);
|
||||
return j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Command parsing with line handling
|
||||
bool ATParser::vsend(const char *command, va_list args)
|
||||
{
|
||||
// Create and send command
|
||||
if (vsprintf(_buffer, command, args) < 0) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; _buffer[i]; i++) {
|
||||
if (putc(_buffer[i]) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Finish with newline
|
||||
for (int i = 0; _delimiter[i]; i++) {
|
||||
if (putc(_delimiter[i]) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
debug_if(dbg_on, "AT> %s\r\n", _buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ATParser::vrecv(const char *response, va_list args)
|
||||
{
|
||||
// Iterate through each line in the expected response
|
||||
while (response[0]) {
|
||||
// Since response is const, we need to copy it into our buffer to
|
||||
// add the line's null terminator and clobber value-matches with asterisks.
|
||||
//
|
||||
// We just use the beginning of the buffer to avoid unnecessary allocations.
|
||||
int i = 0;
|
||||
int offset = 0;
|
||||
|
||||
while (response[i]) {
|
||||
if (memcmp(&response[i+1-_delim_size], _delimiter, _delim_size) == 0) {
|
||||
i++;
|
||||
break;
|
||||
} else if (response[i] == '%' && response[i+1] != '%' && response[i+1] != '*') {
|
||||
_buffer[offset++] = '%';
|
||||
_buffer[offset++] = '*';
|
||||
i++;
|
||||
} else {
|
||||
_buffer[offset++] = response[i++];
|
||||
}
|
||||
}
|
||||
|
||||
// Scanf has very poor support for catching errors
|
||||
// fortunately, we can abuse the %n specifier to determine
|
||||
// if the entire string was matched.
|
||||
_buffer[offset++] = '%';
|
||||
_buffer[offset++] = 'n';
|
||||
_buffer[offset++] = 0;
|
||||
|
||||
// To workaround scanf's lack of error reporting, we actually
|
||||
// make two passes. One checks the validity with the modified
|
||||
// format string that only stores the matched characters (%n).
|
||||
// The other reads in the actual matched values.
|
||||
//
|
||||
// We keep trying the match until we succeed or some other error
|
||||
// derails us.
|
||||
int j = 0;
|
||||
|
||||
while (true) {
|
||||
// Recieve next character
|
||||
int c = getc();
|
||||
if (c < 0) {
|
||||
return false;
|
||||
}
|
||||
_buffer[offset + j++] = c;
|
||||
_buffer[offset + j] = 0;
|
||||
|
||||
// Check for match
|
||||
int count = -1;
|
||||
sscanf(_buffer+offset, _buffer, &count);
|
||||
|
||||
// We only succeed if all characters in the response are matched
|
||||
if (count == j) {
|
||||
debug_if(dbg_on, "AT= %s\r\n", _buffer+offset);
|
||||
// Reuse the front end of the buffer
|
||||
memcpy(_buffer, response, i);
|
||||
_buffer[i] = 0;
|
||||
|
||||
// Store the found results
|
||||
vsscanf(_buffer+offset, _buffer, args);
|
||||
|
||||
// Jump to next line and continue parsing
|
||||
response += i;
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear the buffer when we hit a newline or ran out of space
|
||||
// running out of space usually means we ran into binary data
|
||||
if (j+1 >= _buffer_size - offset ||
|
||||
strcmp(&_buffer[offset + j-_delim_size], _delimiter) == 0) {
|
||||
|
||||
debug_if(dbg_on, "AT< %s", _buffer+offset);
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Mapping to vararg functions
|
||||
int ATParser::printf(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int res = vprintf(format, args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
int ATParser::scanf(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int res = vscanf(format, args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool ATParser::send(const char *command, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, command);
|
||||
bool res = vsend(command, args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool ATParser::recv(const char *response, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, response);
|
||||
bool res = vrecv(response, args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
/* 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.
|
||||
*
|
||||
* @section DESCRIPTION
|
||||
*
|
||||
* Parser for the AT command syntax
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mbed.h"
|
||||
#include <cstdarg>
|
||||
#include "BufferedSerial.h"
|
||||
|
||||
|
||||
/**
|
||||
* Parser class for parsing AT commands
|
||||
*
|
||||
* Here are some examples:
|
||||
* @code
|
||||
* ATParser at = ATParser(serial, "\r\n");
|
||||
* int value;
|
||||
* char buffer[100];
|
||||
*
|
||||
* at.send("AT") && at.recv("OK");
|
||||
* at.send("AT+CWMODE=%d", 3) && at.recv("OK");
|
||||
* at.send("AT+CWMODE?") && at.recv("+CWMODE:%d\r\nOK", &value);
|
||||
* at.recv("+IPD,%d:", &value);
|
||||
* at.read(buffer, value);
|
||||
* at.recv("OK");
|
||||
* @endcode
|
||||
*/
|
||||
class ATParser
|
||||
{
|
||||
private:
|
||||
// Serial information
|
||||
BufferedSerial *_serial;
|
||||
int _buffer_size;
|
||||
char *_buffer;
|
||||
int _timeout;
|
||||
|
||||
// Parsing information
|
||||
const char *_delimiter;
|
||||
int _delim_size;
|
||||
bool dbg_on;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param serial serial interface to use for AT commands
|
||||
* @param buffer_size size of internal buffer for transaction
|
||||
* @param timeout timeout of the connection
|
||||
* @param delimiter string of characters to use as line delimiters
|
||||
*/
|
||||
ATParser(BufferedSerial &serial, const char *delimiter = "\r\n", int buffer_size = 256, int timeout = 8000, bool debug = false) :
|
||||
_serial(&serial),
|
||||
_buffer_size(buffer_size) {
|
||||
_buffer = new char[buffer_size];
|
||||
setTimeout(timeout);
|
||||
setDelimiter(delimiter);
|
||||
debugOn(debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~ATParser() {
|
||||
delete [] _buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows timeout to be changed between commands
|
||||
*
|
||||
* @param timeout timeout of the connection
|
||||
*/
|
||||
void setTimeout(int timeout) {
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets string of characters to use as line delimiters
|
||||
*
|
||||
* @param delimiter string of characters to use as line delimiters
|
||||
*/
|
||||
void setDelimiter(const char *delimiter) {
|
||||
_delimiter = delimiter;
|
||||
_delim_size = strlen(delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows echo to be on or off
|
||||
*
|
||||
* @param echo 1 for echo and 0 turns it off
|
||||
*/
|
||||
void debugOn(uint8_t on) {
|
||||
dbg_on = (on) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an AT command
|
||||
*
|
||||
* Sends a formatted command using printf style formatting
|
||||
* @see ::printf
|
||||
*
|
||||
* @param command printf-like format string of command to send which
|
||||
* is appended with the specified delimiter
|
||||
* @param ... all printf-like arguments to insert into command
|
||||
* @return true only if command is successfully sent
|
||||
*/
|
||||
bool send(const char *command, ...);
|
||||
bool vsend(const char *command, va_list args);
|
||||
|
||||
/**
|
||||
* Recieve an AT response
|
||||
*
|
||||
* Recieves a formatted response using scanf style formatting
|
||||
* @see ::scanf
|
||||
*
|
||||
* Responses are parsed line at a time using the specified delimiter.
|
||||
* Any recieved data that does not match the response is ignored until
|
||||
* a timeout occurs.
|
||||
*
|
||||
* @param response scanf-like format string of response to expect
|
||||
* @param ... all scanf-like arguments to extract from response
|
||||
* @return true only if response is successfully matched
|
||||
*/
|
||||
bool recv(const char *response, ...);
|
||||
bool vrecv(const char *response, va_list args);
|
||||
|
||||
/**
|
||||
* Write a single byte to the underlying stream
|
||||
*
|
||||
* @param c The byte to write
|
||||
* @return The byte that was written or -1 during a timeout
|
||||
*/
|
||||
int putc(char c);
|
||||
|
||||
/**
|
||||
* Get a single byte from the underlying stream
|
||||
*
|
||||
* @return The byte that was read or -1 during a timeout
|
||||
*/
|
||||
int getc();
|
||||
|
||||
/**
|
||||
* Write an array of bytes to the underlying stream
|
||||
*
|
||||
* @param data the array of bytes to write
|
||||
* @param size number of bytes to write
|
||||
* @return number of bytes written or -1 on failure
|
||||
*/
|
||||
int write(const char *data, int size);
|
||||
|
||||
/**
|
||||
* Read an array of bytes from the underlying stream
|
||||
*
|
||||
* @param data the destination for the read bytes
|
||||
* @param size number of bytes to read
|
||||
* @return number of bytes read or -1 on failure
|
||||
*/
|
||||
int read(char *data, int size);
|
||||
|
||||
/**
|
||||
* Direct printf to underlying stream
|
||||
* @see ::printf
|
||||
*
|
||||
* @param format format string to pass to printf
|
||||
* @param ... arguments to printf
|
||||
* @return number of bytes written or -1 on failure
|
||||
*/
|
||||
int printf(const char *format, ...);
|
||||
int vprintf(const char *format, va_list args);
|
||||
|
||||
/**
|
||||
* Direct scanf on underlying stream
|
||||
* @see ::scanf
|
||||
*
|
||||
* @param format format string to pass to scanf
|
||||
* @param ... arguments to scanf
|
||||
* @return number of bytes read or -1 on failure
|
||||
*/
|
||||
int scanf(const char *format, ...);
|
||||
int vscanf(const char *format, va_list args);
|
||||
|
||||
/**
|
||||
* Flushes the underlying stream
|
||||
*/
|
||||
void flush();
|
||||
};
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
/**
|
||||
* @file Buffer.cpp
|
||||
* @brief Software Buffer - Templated Ring Buffer for most data types
|
||||
* @author sam grove
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* Copyright (c) 2013
|
||||
*
|
||||
* 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 "MyBuffer.h"
|
||||
|
||||
template <class T>
|
||||
MyBuffer<T>::MyBuffer(uint32_t size)
|
||||
{
|
||||
_buf = new T [size];
|
||||
_size = size;
|
||||
clear();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
MyBuffer<T>::~MyBuffer()
|
||||
{
|
||||
delete [] _buf;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
uint32_t MyBuffer<T>::getSize()
|
||||
{
|
||||
return this->_size;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void MyBuffer<T>::clear(void)
|
||||
{
|
||||
_wloc = 0;
|
||||
_rloc = 0;
|
||||
memset(_buf, 0, _size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
uint32_t MyBuffer<T>::peek(char c)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// make the linker aware of some possible types
|
||||
template class MyBuffer<uint8_t>;
|
||||
template class MyBuffer<int8_t>;
|
||||
template class MyBuffer<uint16_t>;
|
||||
template class MyBuffer<int16_t>;
|
||||
template class MyBuffer<uint32_t>;
|
||||
template class MyBuffer<int32_t>;
|
||||
template class MyBuffer<uint64_t>;
|
||||
template class MyBuffer<int64_t>;
|
||||
template class MyBuffer<char>;
|
||||
template class MyBuffer<wchar_t>;
|
|
@ -0,0 +1,163 @@
|
|||
|
||||
/**
|
||||
* @file Buffer.h
|
||||
* @brief Software Buffer - Templated Ring Buffer for most data types
|
||||
* @author sam grove
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* Copyright (c) 2013
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MYBUFFER_H
|
||||
#define MYBUFFER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/** A templated software ring buffer
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* #include "mbed.h"
|
||||
* #include "MyBuffer.h"
|
||||
*
|
||||
* MyBuffer <char> buf;
|
||||
*
|
||||
* int main()
|
||||
* {
|
||||
* buf = 'a';
|
||||
* buf.put('b');
|
||||
* char *head = buf.head();
|
||||
* puts(head);
|
||||
*
|
||||
* char whats_in_there[2] = {0};
|
||||
* int pos = 0;
|
||||
*
|
||||
* while(buf.available())
|
||||
* {
|
||||
* whats_in_there[pos++] = buf;
|
||||
* }
|
||||
* printf("%c %c\n", whats_in_there[0], whats_in_there[1]);
|
||||
* buf.clear();
|
||||
* error("done\n\n\n");
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
class MyBuffer
|
||||
{
|
||||
private:
|
||||
T *_buf;
|
||||
volatile uint32_t _wloc;
|
||||
volatile uint32_t _rloc;
|
||||
uint32_t _size;
|
||||
|
||||
public:
|
||||
/** Create a Buffer and allocate memory for it
|
||||
* @param size The size of the buffer
|
||||
*/
|
||||
MyBuffer(uint32_t size = 0x100);
|
||||
|
||||
/** Get the size of the ring buffer
|
||||
* @return the size of the ring buffer
|
||||
*/
|
||||
uint32_t getSize();
|
||||
|
||||
/** Destry a Buffer and release it's allocated memory
|
||||
*/
|
||||
~MyBuffer();
|
||||
|
||||
/** Add a data element into the buffer
|
||||
* @param data Something to add to the buffer
|
||||
*/
|
||||
void put(T data);
|
||||
|
||||
/** Remove a data element from the buffer
|
||||
* @return Pull the oldest element from the buffer
|
||||
*/
|
||||
T get(void);
|
||||
|
||||
/** Get the address to the head of the buffer
|
||||
* @return The address of element 0 in the buffer
|
||||
*/
|
||||
T *head(void);
|
||||
|
||||
/** Reset the buffer to 0. Useful if using head() to parse packeted data
|
||||
*/
|
||||
void clear(void);
|
||||
|
||||
/** Determine if anything is readable in the buffer
|
||||
* @return 1 if something can be read, 0 otherwise
|
||||
*/
|
||||
uint32_t available(void);
|
||||
|
||||
/** Overloaded operator for writing to the buffer
|
||||
* @param data Something to put in the buffer
|
||||
* @return
|
||||
*/
|
||||
MyBuffer &operator= (T data)
|
||||
{
|
||||
put(data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Overloaded operator for reading from the buffer
|
||||
* @return Pull the oldest element from the buffer
|
||||
*/
|
||||
operator int(void)
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
uint32_t peek(char c);
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline void MyBuffer<T>::put(T data)
|
||||
{
|
||||
_buf[_wloc++] = data;
|
||||
_wloc %= (_size-1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T MyBuffer<T>::get(void)
|
||||
{
|
||||
T data_pos = _buf[_rloc++];
|
||||
_rloc %= (_size-1);
|
||||
|
||||
return data_pos;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T *MyBuffer<T>::head(void)
|
||||
{
|
||||
T *data_pos = &_buf[0];
|
||||
|
||||
return data_pos;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline uint32_t MyBuffer<T>::available(void)
|
||||
{
|
||||
return (_wloc == _rloc) ? 0 : 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
/**
|
||||
* @file BufferedSerial.cpp
|
||||
* @brief Software Buffer - Extends mbed Serial functionallity adding irq driven TX and RX
|
||||
* @author sam grove
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* Copyright (c) 2013
|
||||
*
|
||||
* 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 "BufferedSerial.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
BufferedSerial::BufferedSerial(PinName tx, PinName rx, uint32_t buf_size, uint32_t tx_multiple, const char* name)
|
||||
: RawSerial(tx, rx) , _rxbuf(buf_size), _txbuf((uint32_t)(tx_multiple*buf_size))
|
||||
{
|
||||
RawSerial::attach(this, &BufferedSerial::rxIrq, Serial::RxIrq);
|
||||
this->_buf_size = buf_size;
|
||||
this->_tx_multiple = tx_multiple;
|
||||
return;
|
||||
}
|
||||
|
||||
BufferedSerial::~BufferedSerial(void)
|
||||
{
|
||||
RawSerial::attach(NULL, RawSerial::RxIrq);
|
||||
RawSerial::attach(NULL, RawSerial::TxIrq);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int BufferedSerial::readable(void)
|
||||
{
|
||||
return _rxbuf.available(); // note: look if things are in the buffer
|
||||
}
|
||||
|
||||
int BufferedSerial::writeable(void)
|
||||
{
|
||||
return 1; // buffer allows overwriting by design, always true
|
||||
}
|
||||
|
||||
int BufferedSerial::getc(void)
|
||||
{
|
||||
return _rxbuf;
|
||||
}
|
||||
|
||||
int BufferedSerial::putc(int c)
|
||||
{
|
||||
_txbuf = (char)c;
|
||||
BufferedSerial::prime();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int BufferedSerial::puts(const char *s)
|
||||
{
|
||||
if (s != NULL) {
|
||||
const char* ptr = s;
|
||||
|
||||
while(*(ptr) != 0) {
|
||||
_txbuf = *(ptr++);
|
||||
}
|
||||
_txbuf = '\n'; // done per puts definition
|
||||
BufferedSerial::prime();
|
||||
|
||||
return (ptr - s) + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BufferedSerial::printf(const char* format, ...)
|
||||
{
|
||||
char buffer[this->_buf_size];
|
||||
memset(buffer,0,this->_buf_size);
|
||||
int r = 0;
|
||||
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
r = vsprintf(buffer, format, arg);
|
||||
// this may not hit the heap but should alert the user anyways
|
||||
if(r > this->_buf_size) {
|
||||
error("%s %d buffer overwrite (max_buf_size: %d exceeded: %d)!\r\n", __FILE__, __LINE__,this->_buf_size,r);
|
||||
va_end(arg);
|
||||
return 0;
|
||||
}
|
||||
va_end(arg);
|
||||
r = BufferedSerial::write(buffer, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
ssize_t BufferedSerial::write(const void *s, size_t length)
|
||||
{
|
||||
if (s != NULL && length > 0) {
|
||||
const char* ptr = (const char*)s;
|
||||
const char* end = ptr + length;
|
||||
|
||||
while (ptr != end) {
|
||||
_txbuf = *(ptr++);
|
||||
}
|
||||
BufferedSerial::prime();
|
||||
|
||||
return ptr - (const char*)s;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void BufferedSerial::rxIrq(void)
|
||||
{
|
||||
// read from the peripheral and make sure something is available
|
||||
if(serial_readable(&_serial)) {
|
||||
_rxbuf = serial_getc(&_serial); // if so load them into a buffer
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void BufferedSerial::txIrq(void)
|
||||
{
|
||||
// see if there is room in the hardware fifo and if something is in the software fifo
|
||||
while(serial_writable(&_serial)) {
|
||||
if(_txbuf.available()) {
|
||||
serial_putc(&_serial, (int)_txbuf.get());
|
||||
} else {
|
||||
// disable the TX interrupt when there is nothing left to send
|
||||
RawSerial::attach(NULL, RawSerial::TxIrq);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void BufferedSerial::prime(void)
|
||||
{
|
||||
// if already busy then the irq will pick this up
|
||||
if(serial_writable(&_serial)) {
|
||||
RawSerial::attach(NULL, RawSerial::TxIrq); // make sure not to cause contention in the irq
|
||||
BufferedSerial::txIrq(); // only write to hardware in one place
|
||||
RawSerial::attach(this, &BufferedSerial::txIrq, RawSerial::TxIrq);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
|
||||
/**
|
||||
* @file BufferedSerial.h
|
||||
* @brief Software Buffer - Extends mbed Serial functionallity adding irq driven TX and RX
|
||||
* @author sam grove
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* Copyright (c) 2013
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef BUFFEREDSERIAL_H
|
||||
#define BUFFEREDSERIAL_H
|
||||
|
||||
#include "mbed.h"
|
||||
#include "MyBuffer.h"
|
||||
|
||||
/** A serial port (UART) for communication with other serial devices
|
||||
*
|
||||
* Can be used for Full Duplex communication, or Simplex by specifying
|
||||
* one pin as NC (Not Connected)
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* #include "mbed.h"
|
||||
* #include "BufferedSerial.h"
|
||||
*
|
||||
* BufferedSerial pc(USBTX, USBRX);
|
||||
*
|
||||
* int main()
|
||||
* {
|
||||
* while(1)
|
||||
* {
|
||||
* Timer s;
|
||||
*
|
||||
* s.start();
|
||||
* pc.printf("Hello World - buffered\n");
|
||||
* int buffered_time = s.read_us();
|
||||
* wait(0.1f); // give time for the buffer to empty
|
||||
*
|
||||
* s.reset();
|
||||
* printf("Hello World - blocking\n");
|
||||
* int polled_time = s.read_us();
|
||||
* s.stop();
|
||||
* wait(0.1f); // give time for the buffer to empty
|
||||
*
|
||||
* pc.printf("printf buffered took %d us\n", buffered_time);
|
||||
* pc.printf("printf blocking took %d us\n", polled_time);
|
||||
* wait(0.5f);
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class BufferedSerial
|
||||
* @brief Software buffers and interrupt driven tx and rx for Serial
|
||||
*/
|
||||
class BufferedSerial : public RawSerial
|
||||
{
|
||||
private:
|
||||
MyBuffer <char> _rxbuf;
|
||||
MyBuffer <char> _txbuf;
|
||||
uint32_t _buf_size;
|
||||
uint32_t _tx_multiple;
|
||||
|
||||
void rxIrq(void);
|
||||
void txIrq(void);
|
||||
void prime(void);
|
||||
|
||||
public:
|
||||
/** Create a BufferedSerial port, connected to the specified transmit and receive pins
|
||||
* @param tx Transmit pin
|
||||
* @param rx Receive pin
|
||||
* @param buf_size printf() buffer size
|
||||
* @param tx_multiple amount of max printf() present in the internal ring buffer at one time
|
||||
* @param name optional name
|
||||
* @note Either tx or rx may be specified as NC if unused
|
||||
*/
|
||||
BufferedSerial(PinName tx, PinName rx, uint32_t buf_size = 256, uint32_t tx_multiple = 4,const char* name=NULL);
|
||||
|
||||
/** Destroy a BufferedSerial port
|
||||
*/
|
||||
virtual ~BufferedSerial(void);
|
||||
|
||||
/** Check on how many bytes are in the rx buffer
|
||||
* @return 1 if something exists, 0 otherwise
|
||||
*/
|
||||
virtual int readable(void);
|
||||
|
||||
/** Check to see if the tx buffer has room
|
||||
* @return 1 always has room and can overwrite previous content if too small / slow
|
||||
*/
|
||||
virtual int writeable(void);
|
||||
|
||||
/** Get a single byte from the BufferedSerial Port.
|
||||
* Should check readable() before calling this.
|
||||
* @return A byte that came in on the Serial Port
|
||||
*/
|
||||
virtual int getc(void);
|
||||
|
||||
/** Write a single byte to the BufferedSerial Port.
|
||||
* @param c The byte to write to the Serial Port
|
||||
* @return The byte that was written to the Serial Port Buffer
|
||||
*/
|
||||
virtual int putc(int c);
|
||||
|
||||
/** Write a string to the BufferedSerial Port. Must be NULL terminated
|
||||
* @param s The string to write to the Serial Port
|
||||
* @return The number of bytes written to the Serial Port Buffer
|
||||
*/
|
||||
virtual int puts(const char *s);
|
||||
|
||||
/** Write a formatted string to the BufferedSerial Port.
|
||||
* @param format The string + format specifiers to write to the Serial Port
|
||||
* @return The number of bytes written to the Serial Port Buffer
|
||||
*/
|
||||
virtual int printf(const char* format, ...);
|
||||
|
||||
/** Write data to the Buffered Serial Port
|
||||
* @param s A pointer to data to send
|
||||
* @param length The amount of data being pointed to
|
||||
* @return The number of bytes written to the Serial Port Buffer
|
||||
*/
|
||||
virtual ssize_t write(const void *s, std::size_t length);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,169 @@
|
|||
/* ESP8266 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 "ESP8266.h"
|
||||
|
||||
ESP8266::ESP8266(PinName tx, PinName rx, bool debug)
|
||||
: _serial(tx, rx, 1024), _parser(_serial)
|
||||
{
|
||||
_serial.baud(115200);
|
||||
_parser.debugOn(debug);
|
||||
}
|
||||
|
||||
bool ESP8266::startup(int mode)
|
||||
{
|
||||
//only 3 valid modes
|
||||
if(mode < 1 || mode > 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return reset()
|
||||
&& _parser.send("AT+CWMODE=%d", mode)
|
||||
&& _parser.recv("OK")
|
||||
&& _parser.send("AT+CIPMUX=1")
|
||||
&& _parser.recv("OK");
|
||||
}
|
||||
|
||||
bool ESP8266::reset(void)
|
||||
{
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (_parser.send("AT+RST")
|
||||
&& _parser.recv("OK\r\nready")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ESP8266::dhcp(bool enabled, int mode)
|
||||
{
|
||||
//only 3 valid modes
|
||||
if(mode < 0 || mode > 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _parser.send("AT+CWDHCP=%d,%d", enabled?1:0, mode)
|
||||
&& _parser.recv("OK");
|
||||
}
|
||||
|
||||
bool ESP8266::connect(const char *ap, const char *passPhrase)
|
||||
{
|
||||
return _parser.send("AT+CWJAP=\"%s\",\"%s\"", ap, passPhrase)
|
||||
&& _parser.recv("OK");
|
||||
}
|
||||
|
||||
bool ESP8266::disconnect(void)
|
||||
{
|
||||
return _parser.send("AT+CWQAP") && _parser.recv("OK");
|
||||
}
|
||||
|
||||
const char *ESP8266::getIPAddress(void)
|
||||
{
|
||||
if (!(_parser.send("AT+CIFSR")
|
||||
&& _parser.recv("+CIFSR:STAIP,\"%[^\"]\"", _ip_buffer)
|
||||
&& _parser.recv("OK"))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _ip_buffer;
|
||||
}
|
||||
|
||||
const char *ESP8266::getMACAddress(void)
|
||||
{
|
||||
if (!(_parser.send("AT+CIFSR")
|
||||
&& _parser.recv("+CIFSR:STAMAC,\"%[^\"]\"", _mac_buffer)
|
||||
&& _parser.recv("OK"))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _mac_buffer;
|
||||
}
|
||||
|
||||
bool ESP8266::isConnected(void)
|
||||
{
|
||||
return getIPAddress() != 0;
|
||||
}
|
||||
|
||||
bool ESP8266::open(const char *type, int id, const char* addr, int port)
|
||||
{
|
||||
//IDs only 0-4
|
||||
if(id > 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port)
|
||||
&& _parser.recv("OK");
|
||||
}
|
||||
|
||||
bool ESP8266::send(int id, const void *data, uint32_t amount)
|
||||
{
|
||||
//May take a second try if device is busy
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
if (_parser.send("AT+CIPSEND=%d,%d", id, amount)
|
||||
&& _parser.recv(">")
|
||||
&& _parser.write((char*)data, (int)amount) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t ESP8266::recv(int id, void *data, uint32_t amount)
|
||||
{
|
||||
uint32_t recv_amount;
|
||||
int recv_id;
|
||||
|
||||
if (!(_parser.recv("+IPD,%d,%d:", &recv_id, &recv_amount)
|
||||
&& recv_id == id
|
||||
&& recv_amount <= amount
|
||||
&& _parser.read((char*)data, recv_amount)
|
||||
&& _parser.recv("OK"))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return recv_amount;
|
||||
}
|
||||
|
||||
bool ESP8266::close(int id)
|
||||
{
|
||||
//May take a second try if device is busy
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
if (_parser.send("AT+CIPCLOSE=%d", id)
|
||||
&& _parser.recv("OK")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ESP8266::setTimeout(uint32_t timeout_ms)
|
||||
{
|
||||
_parser.setTimeout(timeout_ms);
|
||||
}
|
||||
|
||||
bool ESP8266::readable()
|
||||
{
|
||||
return _serial.readable();
|
||||
}
|
||||
|
||||
bool ESP8266::writeable()
|
||||
{
|
||||
return _serial.writeable();
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
/* ESP8266Interface 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.
|
||||
*/
|
||||
|
||||
#ifndef ESP8266_H
|
||||
#define ESP8266_H
|
||||
|
||||
#include "ATParser.h"
|
||||
|
||||
/** ESP8266Interface class.
|
||||
This is an interface to a ESP8266 radio.
|
||||
*/
|
||||
class ESP8266
|
||||
{
|
||||
public:
|
||||
ESP8266(PinName tx, PinName rx, bool debug=false);
|
||||
|
||||
/**
|
||||
* Startup the ESP8266
|
||||
*
|
||||
* @param mode mode of WIFI 1-client, 2-host, 3-both
|
||||
* @return true only if ESP8266 was setup correctly
|
||||
*/
|
||||
bool startup(int mode);
|
||||
|
||||
/**
|
||||
* Reset ESP8266
|
||||
*
|
||||
* @return true only if ESP8266 resets successfully
|
||||
*/
|
||||
bool reset(void);
|
||||
|
||||
/**
|
||||
* Enable/Disable DHCP
|
||||
*
|
||||
* @param enabled DHCP enabled when true
|
||||
* @param mode mode of DHCP 0-softAP, 1-station, 2-both
|
||||
* @return true only if ESP8266 enables/disables DHCP successfully
|
||||
*/
|
||||
bool dhcp(bool enabled, int mode);
|
||||
|
||||
/**
|
||||
* Connect ESP8266 to AP
|
||||
*
|
||||
* @param ap the name of the AP
|
||||
* @param passPhrase the password of AP
|
||||
* @return true only if ESP8266 is connected successfully
|
||||
*/
|
||||
bool connect(const char *ap, const char *passPhrase);
|
||||
|
||||
/**
|
||||
* Disconnect ESP8266 from AP
|
||||
*
|
||||
* @return true only if ESP8266 is disconnected successfully
|
||||
*/
|
||||
bool disconnect(void);
|
||||
|
||||
/**
|
||||
* Get the IP address of ESP8266
|
||||
*
|
||||
* @return null-teriminated IP address or null if no IP address is assigned
|
||||
*/
|
||||
const char *getIPAddress(void);
|
||||
|
||||
/**
|
||||
* Get the MAC address of ESP8266
|
||||
*
|
||||
* @return null-terminated MAC address or null if no MAC address is assigned
|
||||
*/
|
||||
const char *getMACAddress(void);
|
||||
|
||||
/**
|
||||
* Check if ESP8266 is conenected
|
||||
*
|
||||
* @return true only if the chip has an IP address
|
||||
*/
|
||||
bool isConnected(void);
|
||||
|
||||
/**
|
||||
* Open a socketed connection
|
||||
*
|
||||
* @param type the type of socket to open "UDP" or "TCP"
|
||||
* @param id id to give the new socket, valid 0-4
|
||||
* @param port port to open connection with
|
||||
* @param addr the IP address of the destination
|
||||
* @return true only if socket opened successfully
|
||||
*/
|
||||
bool open(const char *type, int id, const char* addr, int port);
|
||||
|
||||
/**
|
||||
* Sends data to an open socket
|
||||
*
|
||||
* @param id id of socket to send to
|
||||
* @param data data to be sent
|
||||
* @param amount amount of data to be sent - max 1024
|
||||
* @return true only if data sent successfully
|
||||
*/
|
||||
bool send(int id, const void *data, uint32_t amount);
|
||||
|
||||
/**
|
||||
* Receives data from an open socket
|
||||
*
|
||||
* @param id id to receive from
|
||||
* @param data placeholder for returned information
|
||||
* @param amount number of bytes to be received
|
||||
* @return the number of bytes received
|
||||
*/
|
||||
int32_t recv(int id, void *data, uint32_t amount);
|
||||
|
||||
/**
|
||||
* Closes a socket
|
||||
*
|
||||
* @param id id of socket to close, valid only 0-4
|
||||
* @return true only if socket is closed successfully
|
||||
*/
|
||||
bool close(int id);
|
||||
|
||||
/**
|
||||
* Allows timeout to be changed between commands
|
||||
*
|
||||
* @param timeout_ms timeout of the connection
|
||||
*/
|
||||
void setTimeout(uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* Checks if data is available
|
||||
*/
|
||||
bool readable();
|
||||
|
||||
/**
|
||||
* Checks if data can be written
|
||||
*/
|
||||
bool writeable();
|
||||
|
||||
private:
|
||||
BufferedSerial _serial;
|
||||
ATParser _parser;
|
||||
|
||||
char _ip_buffer[16];
|
||||
char _mac_buffer[18];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,232 @@
|
|||
/* ESP8266 implementation of NetworkInterfaceAPI
|
||||
* 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 "ESP8266Interface.h"
|
||||
|
||||
// Various timeouts for different ESP8266 operations
|
||||
#define ESP8266_CONNECT_TIMEOUT 15000
|
||||
#define ESP8266_SEND_TIMEOUT 500
|
||||
#define ESP8266_RECV_TIMEOUT 0
|
||||
#define ESP8266_MISC_TIMEOUT 500
|
||||
|
||||
|
||||
// ESP8266Interface implementation
|
||||
ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug)
|
||||
: _esp(tx, rx, debug)
|
||||
{
|
||||
memset(_ids, 0, sizeof(_ids));
|
||||
}
|
||||
|
||||
int ESP8266Interface::connect(
|
||||
const char *ssid,
|
||||
const char *pass,
|
||||
nsapi_security_t security)
|
||||
{
|
||||
_esp.setTimeout(ESP8266_CONNECT_TIMEOUT);
|
||||
|
||||
if (!_esp.startup(3)) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (!_esp.dhcp(true, 1)) {
|
||||
return NSAPI_ERROR_DHCP_FAILURE;
|
||||
}
|
||||
|
||||
if (!_esp.connect(ssid, pass)) {
|
||||
return NSAPI_ERROR_NO_CONNECTION;
|
||||
}
|
||||
|
||||
if (!_esp.getIPAddress()) {
|
||||
return NSAPI_ERROR_DHCP_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ESP8266Interface::disconnect()
|
||||
{
|
||||
_esp.setTimeout(ESP8266_MISC_TIMEOUT);
|
||||
|
||||
if (!_esp.disconnect()) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *ESP8266Interface::get_ip_address()
|
||||
{
|
||||
return _esp.getIPAddress();
|
||||
}
|
||||
|
||||
const char *ESP8266Interface::get_mac_address()
|
||||
{
|
||||
return _esp.getMACAddress();
|
||||
}
|
||||
|
||||
struct esp8266_socket {
|
||||
int id;
|
||||
nsapi_protocol_t proto;
|
||||
bool connected;
|
||||
};
|
||||
|
||||
void *ESP8266Interface::socket_create(nsapi_protocol_t proto)
|
||||
{
|
||||
// Look for an unused socket
|
||||
int id = -1;
|
||||
|
||||
for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
|
||||
if (!_ids[i]) {
|
||||
id = i;
|
||||
_ids[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (id == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct esp8266_socket *socket = new struct esp8266_socket;
|
||||
if (!socket) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
socket->id = id;
|
||||
socket->proto = proto;
|
||||
socket->connected = false;
|
||||
return socket;
|
||||
}
|
||||
|
||||
void ESP8266Interface::socket_destroy(void *handle)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
_ids[socket->id] = false;
|
||||
delete socket;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_set_option(void *handle, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_get_option(void *handle, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_bind(void *handle, int port)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_listen(void *handle, int backlog)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_connect(void *handle, const SocketAddress &addr)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
_esp.setTimeout(ESP8266_MISC_TIMEOUT);
|
||||
|
||||
const char *proto = (socket->proto == NSAPI_UDP) ? "UDP" : "TCP";
|
||||
if (!_esp.open(proto, socket->id, addr.get_ip_address(), addr.get_port())) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
socket->connected = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ESP8266Interface::socket_is_connected(void *handle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_accept(void *handle, void **connection)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_send(void *handle, const void *data, unsigned size)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
_esp.setTimeout(ESP8266_SEND_TIMEOUT);
|
||||
|
||||
if (!_esp.send(socket->id, data, size)) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_recv(void *handle, void *data, unsigned size)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
_esp.setTimeout(ESP8266_RECV_TIMEOUT);
|
||||
|
||||
int32_t recv = _esp.recv(socket->id, data, size);
|
||||
if (recv < 0) {
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
return recv;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
if (!socket->connected) {
|
||||
int err = socket_connect(socket, addr);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return socket_send(socket, data, size);
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
return socket_recv(socket, data, size);
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_close(void *handle, bool shutdown)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
_esp.setTimeout(ESP8266_MISC_TIMEOUT);
|
||||
|
||||
if (!_esp.close(socket->id)) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ESP8266Interface::socket_attach_accept(void *handle, void (*callback)(void *), void *id)
|
||||
{
|
||||
}
|
||||
|
||||
void ESP8266Interface::socket_attach_send(void *handle, void (*callback)(void *), void *id)
|
||||
{
|
||||
}
|
||||
|
||||
void ESP8266Interface::socket_attach_recv(void *handle, void (*callback)(void *), void *id)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
/* ESP8266 implementation of NetworkInterfaceAPI
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ESP8266_INTERFACE_H
|
||||
#define ESP8266_INTERFACE_H
|
||||
|
||||
#include "WiFiInterface.h"
|
||||
#include "ESP8266.h"
|
||||
|
||||
#define ESP8266_SOCKET_COUNT 5
|
||||
|
||||
/** ESP8266Interface class
|
||||
* Implementation of the NetworkInterface for the ESP8266
|
||||
*/
|
||||
class ESP8266Interface : public WiFiInterface
|
||||
{
|
||||
public:
|
||||
/** ESP8266Interface lifetime
|
||||
/param tx TX pin
|
||||
/param rx RX pin
|
||||
/param debug Enable debugging
|
||||
*/
|
||||
ESP8266Interface(PinName tx, PinName rx, bool debug = false);
|
||||
|
||||
/** Start the interface
|
||||
/param ssid Name of the network to connect to
|
||||
/param pass Security passphrase to connect to the network
|
||||
/param security Type of encryption for connection
|
||||
/return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int connect(
|
||||
const char *ssid,
|
||||
const char *pass,
|
||||
nsapi_security_t security = NSAPI_SECURITY_NONE);
|
||||
|
||||
/** Stop the interface
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int disconnect();
|
||||
|
||||
/** Get the internally stored IP address
|
||||
/return IP address of the interface or null if not yet connected
|
||||
*/
|
||||
virtual const char *get_ip_address();
|
||||
|
||||
/** Get the internally stored MAC address
|
||||
/return MAC address of the interface
|
||||
*/
|
||||
virtual const char *get_mac_address();
|
||||
|
||||
protected:
|
||||
/** Create a socket
|
||||
/param proto The type of socket to open, TCP or UDP
|
||||
/return The alocated socket or null on failure
|
||||
*/
|
||||
virtual void *socket_create(nsapi_protocol_t proto);
|
||||
|
||||
/** Destroy a socket
|
||||
/param socket Previously allocated socket
|
||||
*/
|
||||
virtual void socket_destroy(void *handle);
|
||||
|
||||
/** Set socket options
|
||||
\param handle Socket handle
|
||||
\param optname Option ID
|
||||
\param optval Option value
|
||||
\param optlen Length of the option value
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_set_option(void *handle, int optname, const void *optval, unsigned int optlen);
|
||||
|
||||
/** Get socket options
|
||||
\param handle Socket handle
|
||||
\param optname Option ID
|
||||
\param optval Buffer pointer where to write the option value
|
||||
\param optlen Length of the option value
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_get_option(void *handle, int optname, void *optval, unsigned int *optlen);
|
||||
|
||||
/** Bind a server socket to a specific port
|
||||
\param handle Socket handle
|
||||
\param port The port to listen for incoming connections on
|
||||
\return 0 on success, negative on failure.
|
||||
*/
|
||||
virtual int socket_bind(void *handle, int port);
|
||||
|
||||
/** Start listening for incoming connections
|
||||
\param handle Socket handle
|
||||
\param backlog Number of pending connections that can be queued up at any
|
||||
one time [Default: 1]
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_listen(void *handle, int backlog);
|
||||
|
||||
/** Connects this TCP socket to the server
|
||||
\param handle Socket handle
|
||||
\param address SocketAddress to connect to
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_connect(void *handle, const SocketAddress &address);
|
||||
|
||||
/** Check if the socket is connected
|
||||
\param handle Socket handle
|
||||
\return true if connected, false otherwise
|
||||
*/
|
||||
virtual bool socket_is_connected(void *handle);
|
||||
|
||||
/** Accept a new connection.
|
||||
\param handle Socket handle
|
||||
\param socket A TCPSocket instance that will handle the incoming connection.
|
||||
\return 0 on success, negative on failure.
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_accept(void *handle, void **connection);
|
||||
|
||||
/** Send data to the remote host
|
||||
\param handle Socket handle
|
||||
\param data The buffer to send to the host
|
||||
\param size The length of the buffer to send
|
||||
\return Number of written bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_send(void *handle, const void *data, unsigned size);
|
||||
|
||||
/** Receive data from the remote host
|
||||
\param handle Socket handle
|
||||
\param data The buffer in which to store the data received from the host
|
||||
\param size The maximum length of the buffer
|
||||
\return Number of received bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_recv(void *handle, void *data, unsigned size);
|
||||
|
||||
/** Send a packet to a remote endpoint
|
||||
\param handle Socket handle
|
||||
\param address The remote SocketAddress
|
||||
\param data The packet to be sent
|
||||
\param size The length of the packet to be sent
|
||||
\return the number of written bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size);
|
||||
|
||||
/** Receive a packet from a remote endpoint
|
||||
\param handle Socket handle
|
||||
\param address Destination for the remote SocketAddress or null
|
||||
\param buffer The buffer for storing the incoming packet data
|
||||
If a packet is too long to fit in the supplied buffer,
|
||||
excess bytes are discarded
|
||||
\param size The length of the buffer
|
||||
\return the number of received bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size);
|
||||
|
||||
/** Close the socket
|
||||
\param handle Socket handle
|
||||
\param shutdown free the left-over data in message queues
|
||||
*/
|
||||
virtual int socket_close(void *handle, bool shutdown);
|
||||
|
||||
/** Register a callback on when a new connection is ready
|
||||
\param handle Socket handle
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
\param id Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach_accept(void *handle, void (*callback)(void *), void *id);
|
||||
|
||||
/** Register a callback on when send is ready
|
||||
\param handle Socket handle
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
\param id Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach_send(void *handle, void (*callback)(void *), void *id);
|
||||
|
||||
/** Register a callback on when recv is ready
|
||||
\param handle Socket handle
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
\param id Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach_recv(void *handle, void (*callback)(void *), void *id);
|
||||
|
||||
private:
|
||||
ESP8266 _esp;
|
||||
bool _ids[ESP8266_SOCKET_COUNT];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue