Update IDF to aaf1239 (#1539)

* fix sdmmc config

* Fix warnings in EEPROM

from @Curclamas

* remove leftover TAG in EEPROM

* Initial add of @stickbreaker i2c

* Add log_n

* fix warnings when log is off

* i2c code clean up and reorganization

* add flags to interrupt allocator

* fix sdmmc config

* Fix warnings in EEPROM

from @Curclamas

* remove leftover TAG in EEPROM

* fix errors with latest IDF

* fix debug optimization (#1365)

incorrect optimization for debugging tick markers.

* Fix some missing BT header

* Change BTSerial log calls

* Update BLE lib

* Arduino-ESP32 release management scripted (#1515)

* Calculate an absolute path for a custom partitions table (#1452)

* * Arduino-ESP32 release management scripted
(ready-to-merge)

* * secure env for espressif/arduino-esp32

* * build tests enabled
* gitter webhook enabled

* * gitter room link fixed
* better comment

* * filepaths fixed

* BT Serial adjustments

* * don't run sketch builds & tests for tagged builds

* Return false from WiFi.hostByName() if hostname is not resolved

* Free BT Memory when BT is not used

* WIFI_MODE_NULL is not supported anymore

* Select some key examples to build with PlatformIO to save some time

* Update BLE lib

* Fixed BLE lib

* Major WiFi overhaul

- auto reconnect on connection loss now works
- moved to event groups
- some code clean up and procedure optimizations
- new methods to get a more elaborate system ststus

* Add cmake tests to travis

* Add initial AsyncUDP

* Add NetBIOS lib and fix CMake includes

* Add Initial WebServer

* Fix WebServer and examples

* travis not quiting on build fail

* Try different travis build

* Update IDF to aaf1239

* Fix WPS Example

* fix script permission and add some fail tests to sketch builder

* Add missing space in WiFiClient::write(Stream &stream)
This commit is contained in:
Me No Dev
2018-06-27 09:01:06 +02:00
committed by GitHub
parent 7abd5862ed
commit a59eafbc9d
626 changed files with 39585 additions and 16687 deletions

View File

@ -0,0 +1,51 @@
#include "WiFi.h"
#include "AsyncUDP.h"
const char * ssid = "***********";
const char * password = "***********";
AsyncUDP udp;
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed");
while(1) {
delay(1000);
}
}
if(udp.connect(IPAddress(192,168,1,100), 1234)) {
Serial.println("UDP connected");
udp.onPacket([](AsyncUDPPacket packet) {
Serial.print("UDP Packet Type: ");
Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast");
Serial.print(", From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.print(packet.remotePort());
Serial.print(", To: ");
Serial.print(packet.localIP());
Serial.print(":");
Serial.print(packet.localPort());
Serial.print(", Length: ");
Serial.print(packet.length());
Serial.print(", Data: ");
Serial.write(packet.data(), packet.length());
Serial.println();
//reply to the client
packet.printf("Got %u bytes of data", packet.length());
});
//Send unicast
udp.print("Hello Server!");
}
}
void loop()
{
delay(1000);
//Send broadcast on port 1234
udp.broadcastTo("Anyone here?", 1234);
}

View File

@ -0,0 +1,52 @@
#include "WiFi.h"
#include "AsyncUDP.h"
const char * ssid = "***********";
const char * password = "***********";
AsyncUDP udp;
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed");
while(1) {
delay(1000);
}
}
if(udp.listenMulticast(IPAddress(239,1,2,3), 1234)) {
Serial.print("UDP Listening on IP: ");
Serial.println(WiFi.localIP());
udp.onPacket([](AsyncUDPPacket packet) {
Serial.print("UDP Packet Type: ");
Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast");
Serial.print(", From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.print(packet.remotePort());
Serial.print(", To: ");
Serial.print(packet.localIP());
Serial.print(":");
Serial.print(packet.localPort());
Serial.print(", Length: ");
Serial.print(packet.length());
Serial.print(", Data: ");
Serial.write(packet.data(), packet.length());
Serial.println();
//reply to the client
packet.printf("Got %u bytes of data", packet.length());
});
//Send multicast
udp.print("Hello!");
}
}
void loop()
{
delay(1000);
//Send multicast
udp.print("Anyone here?");
}

View File

@ -0,0 +1,50 @@
#include "WiFi.h"
#include "AsyncUDP.h"
const char * ssid = "***********";
const char * password = "***********";
AsyncUDP udp;
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed");
while(1) {
delay(1000);
}
}
if(udp.listen(1234)) {
Serial.print("UDP Listening on IP: ");
Serial.println(WiFi.localIP());
udp.onPacket([](AsyncUDPPacket packet) {
Serial.print("UDP Packet Type: ");
Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast");
Serial.print(", From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.print(packet.remotePort());
Serial.print(", To: ");
Serial.print(packet.localIP());
Serial.print(":");
Serial.print(packet.localPort());
Serial.print(", Length: ");
Serial.print(packet.length());
Serial.print(", Data: ");
Serial.write(packet.data(), packet.length());
Serial.println();
//reply to the client
packet.printf("Got %u bytes of data", packet.length());
});
}
}
void loop()
{
delay(1000);
//Send broadcast
udp.broadcast("Anyone here?");
}

View File

@ -0,0 +1,33 @@
#######################################
# Syntax Coloring Map For Ultrasound
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
AsyncUDP KEYWORD1
AsyncUDPPacket KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
connect KEYWORD2
connected KEYWORD2
listen KEYWORD2
listenMulticast KEYWORD2
close KEYWORD2
write KEYWORD2
broadcast KEYWORD2
onPacket KEYWORD2
data KEYWORD2
length KEYWORD2
localIP KEYWORD2
localPort KEYWORD2
remoteIP KEYWORD2
remotePort KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -0,0 +1,17 @@
{
"name":"AsyncUDP",
"description":"Asynchronous UDP Library for ESP32",
"keywords":"async,udp,server,client,multicast,broadcast",
"authors":
{
"name": "Hristo Gochkov",
"maintainer": true
},
"repository":
{
"type": "git",
"url": "https://github.com/me-no-dev/ESPAsyncUDP.git"
},
"frameworks": "arduino",
"platforms":"espressif"
}

View File

@ -0,0 +1,9 @@
name=ESP32 Async UDP
version=1.0.0
author=Me-No-Dev
maintainer=Me-No-Dev
sentence=Async UDP Library for ESP32
paragraph=Async UDP Library for ESP32
category=Other
url=https://github.com/me-no-dev/ESPAsyncUDP
architectures=*

View File

@ -0,0 +1,846 @@
#include "Arduino.h"
#include "AsyncUDP.h"
extern "C" {
#include "lwip/opt.h"
#include "lwip/inet.h"
#include "lwip/udp.h"
#include "lwip/igmp.h"
#include "lwip/ip_addr.h"
#include "lwip/mld6.h"
#include <esp_err.h>
#include <esp_wifi.h>
}
#include "lwip/priv/tcpip_priv.h"
typedef struct {
struct tcpip_api_call call;
udp_pcb * pcb;
const ip_addr_t *addr;
uint16_t port;
struct pbuf *pb;
struct netif *netif;
err_t err;
} udp_api_call_t;
static err_t _udp_connect_api(struct tcpip_api_call *api_call_msg){
udp_api_call_t * msg = (udp_api_call_t *)api_call_msg;
msg->err = udp_connect(msg->pcb, msg->addr, msg->port);
return msg->err;
}
static err_t _udp_connect(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port){
udp_api_call_t msg;
msg.pcb = pcb;
msg.addr = addr;
msg.port = port;
tcpip_api_call(_udp_connect_api, (struct tcpip_api_call*)&msg);
return msg.err;
}
static err_t _udp_disconnect_api(struct tcpip_api_call *api_call_msg){
udp_api_call_t * msg = (udp_api_call_t *)api_call_msg;
msg->err = 0;
udp_disconnect(msg->pcb);
return msg->err;
}
static void _udp_disconnect(struct udp_pcb *pcb){
udp_api_call_t msg;
msg.pcb = pcb;
tcpip_api_call(_udp_disconnect_api, (struct tcpip_api_call*)&msg);
}
static err_t _udp_remove_api(struct tcpip_api_call *api_call_msg){
udp_api_call_t * msg = (udp_api_call_t *)api_call_msg;
msg->err = 0;
udp_remove(msg->pcb);
return msg->err;
}
static void _udp_remove(struct udp_pcb *pcb){
udp_api_call_t msg;
msg.pcb = pcb;
tcpip_api_call(_udp_remove_api, (struct tcpip_api_call*)&msg);
}
static err_t _udp_bind_api(struct tcpip_api_call *api_call_msg){
udp_api_call_t * msg = (udp_api_call_t *)api_call_msg;
msg->err = udp_bind(msg->pcb, msg->addr, msg->port);
return msg->err;
}
static err_t _udp_bind(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port){
udp_api_call_t msg;
msg.pcb = pcb;
msg.addr = addr;
msg.port = port;
tcpip_api_call(_udp_bind_api, (struct tcpip_api_call*)&msg);
return msg.err;
}
static err_t _udp_sendto_api(struct tcpip_api_call *api_call_msg){
udp_api_call_t * msg = (udp_api_call_t *)api_call_msg;
msg->err = udp_sendto(msg->pcb, msg->pb, msg->addr, msg->port);
return msg->err;
}
static err_t _udp_sendto(struct udp_pcb *pcb, struct pbuf *pb, const ip_addr_t *addr, u16_t port){
udp_api_call_t msg;
msg.pcb = pcb;
msg.addr = addr;
msg.port = port;
msg.pb = pb;
tcpip_api_call(_udp_sendto_api, (struct tcpip_api_call*)&msg);
return msg.err;
}
static err_t _udp_sendto_if_api(struct tcpip_api_call *api_call_msg){
udp_api_call_t * msg = (udp_api_call_t *)api_call_msg;
msg->err = udp_sendto_if(msg->pcb, msg->pb, msg->addr, msg->port, msg->netif);
return msg->err;
}
static err_t _udp_sendto_if(struct udp_pcb *pcb, struct pbuf *pb, const ip_addr_t *addr, u16_t port, struct netif *netif){
udp_api_call_t msg;
msg.pcb = pcb;
msg.addr = addr;
msg.port = port;
msg.pb = pb;
msg.netif = netif;
tcpip_api_call(_udp_sendto_if_api, (struct tcpip_api_call*)&msg);
return msg.err;
}
typedef struct {
void *arg;
udp_pcb *pcb;
pbuf *pb;
const ip_addr_t *addr;
uint16_t port;
struct netif * netif;
} lwip_event_packet_t;
static xQueueHandle _udp_queue;
static volatile TaskHandle_t _udp_task_handle = NULL;
static void _udp_task(void *pvParameters){
lwip_event_packet_t * e = NULL;
for (;;) {
if(xQueueReceive(_udp_queue, &e, portMAX_DELAY) == pdTRUE){
if(!e->pb){
free((void*)(e));
break;
}
AsyncUDP::_s_recv(e->arg, e->pcb, e->pb, e->addr, e->port, e->netif);
free((void*)(e));
}
}
_udp_task_handle = NULL;
vTaskDelete(NULL);
}
static bool _udp_task_start(){
if(!_udp_queue){
_udp_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *));
if(!_udp_queue){
return false;
}
}
if(!_udp_task_handle){
xTaskCreate(_udp_task, "async_udp", 4096, NULL, 3, (TaskHandle_t*)&_udp_task_handle);
if(!_udp_task_handle){
return false;
}
}
return true;
}
static bool _udp_task_post(void *arg, udp_pcb *pcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif *netif)
{
if(!_udp_task_handle || !_udp_queue){
return false;
}
lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t));
if(!e){
return false;
}
e->arg = arg;
e->pcb = pcb;
e->pb = pb;
e->addr = addr;
e->port = port;
e->netif = netif;
if (xQueueSend(_udp_queue, &e, portMAX_DELAY) != pdPASS) {
free((void*)(e));
return false;
}
return true;
}
static void _udp_recv(void *arg, udp_pcb *pcb, pbuf *pb, const ip_addr_t *addr, uint16_t port)
{
while(pb != NULL) {
pbuf * this_pb = pb;
pb = pb->next;
this_pb->next = NULL;
if(!_udp_task_post(arg, pcb, this_pb, addr, port, ip_current_input_netif())){
pbuf_free(this_pb);
}
}
}
/*
static bool _udp_task_stop(){
if(!_udp_task_post(NULL, NULL, NULL, NULL, 0, NULL)){
return false;
}
while(_udp_task_handle){
vTaskDelay(10);
}
lwip_event_packet_t * e;
while (xQueueReceive(_udp_queue, &e, 0) == pdTRUE) {
if(e->pb){
pbuf_free(e->pb);
}
free((void*)(e));
}
vQueueDelete(_udp_queue);
_udp_queue = NULL;
}
*/
#define UDP_MUTEX_LOCK() //xSemaphoreTake(_lock, portMAX_DELAY)
#define UDP_MUTEX_UNLOCK() //xSemaphoreGive(_lock)
AsyncUDPMessage::AsyncUDPMessage(size_t size)
{
_index = 0;
if(size > CONFIG_TCP_MSS) {
size = CONFIG_TCP_MSS;
}
_size = size;
_buffer = (uint8_t *)malloc(size);
}
AsyncUDPMessage::~AsyncUDPMessage()
{
if(_buffer) {
free(_buffer);
}
}
size_t AsyncUDPMessage::write(const uint8_t *data, size_t len)
{
if(_buffer == NULL) {
return 0;
}
size_t s = space();
if(len > s) {
len = s;
}
memcpy(_buffer + _index, data, len);
_index += len;
return len;
}
size_t AsyncUDPMessage::write(uint8_t data)
{
return write(&data, 1);
}
size_t AsyncUDPMessage::space()
{
if(_buffer == NULL) {
return 0;
}
return _size - _index;
}
uint8_t * AsyncUDPMessage::data()
{
return _buffer;
}
size_t AsyncUDPMessage::length()
{
return _index;
}
void AsyncUDPMessage::flush()
{
_index = 0;
}
AsyncUDPPacket::AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *raddr, uint16_t rport, struct netif * ntif)
{
_udp = udp;
_pb = pb;
_if = TCPIP_ADAPTER_IF_MAX;
_data = (uint8_t*)(pb->payload);
_len = pb->len;
_index = 0;
//memcpy(&_remoteIp, raddr, sizeof(ip_addr_t));
_remoteIp.type = raddr->type;
_localIp.type = _remoteIp.type;
udp_hdr* udphdr = reinterpret_cast<udp_hdr*>(_data - UDP_HLEN);
_localPort = ntohs(udphdr->dest);
_remotePort = ntohs(udphdr->src);
if (_remoteIp.type == IPADDR_TYPE_V4) {
struct ip_hdr * iphdr = (struct ip_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP_HLEN);
_localIp.u_addr.ip4.addr = iphdr->dest.addr;
_remoteIp.u_addr.ip4.addr = iphdr->src.addr;
} else {
struct ip6_hdr * ip6hdr = (struct ip6_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP6_HLEN);
memcpy(&_localIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16);
memcpy(&_remoteIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->src.addr, 16);
}
struct netif * netif = NULL;
void * nif = NULL;
int i;
for (i=0; i<TCPIP_ADAPTER_IF_MAX; i++) {
tcpip_adapter_get_netif ((tcpip_adapter_if_t)i, &nif);
netif = (struct netif *)nif;
if (netif && netif == ntif) {
_if = (tcpip_adapter_if_t)i;
break;
}
}
}
AsyncUDPPacket::~AsyncUDPPacket()
{
pbuf_free(_pb);
}
uint8_t * AsyncUDPPacket::data()
{
return _data;
}
size_t AsyncUDPPacket::length()
{
return _len;
}
int AsyncUDPPacket::available(){
return _len - _index;
}
size_t AsyncUDPPacket::read(uint8_t *data, size_t len){
size_t i;
size_t a = _len - _index;
if(len > a){
len = a;
}
for(i=0;i<len;i++){
data[i] = read();
}
return len;
}
int AsyncUDPPacket::read(){
if(_index < _len){
return _data[_index++];
}
return -1;
}
int AsyncUDPPacket::peek(){
if(_index < _len){
return _data[_index];
}
return -1;
}
void AsyncUDPPacket::flush(){
_index = _len;
}
tcpip_adapter_if_t AsyncUDPPacket::interface()
{
return _if;
}
IPAddress AsyncUDPPacket::localIP()
{
if(_localIp.type != IPADDR_TYPE_V4){
return IPAddress();
}
return IPAddress(_localIp.u_addr.ip4.addr);
}
IPv6Address AsyncUDPPacket::localIPv6()
{
if(_localIp.type != IPADDR_TYPE_V6){
return IPv6Address();
}
return IPv6Address(_localIp.u_addr.ip6.addr);
}
uint16_t AsyncUDPPacket::localPort()
{
return _localPort;
}
IPAddress AsyncUDPPacket::remoteIP()
{
if(_remoteIp.type != IPADDR_TYPE_V4){
return IPAddress();
}
return IPAddress(_remoteIp.u_addr.ip4.addr);
}
IPv6Address AsyncUDPPacket::remoteIPv6()
{
if(_remoteIp.type != IPADDR_TYPE_V6){
return IPv6Address();
}
return IPv6Address(_remoteIp.u_addr.ip6.addr);
}
uint16_t AsyncUDPPacket::remotePort()
{
return _remotePort;
}
bool AsyncUDPPacket::isIPv6()
{
return _localIp.type == IPADDR_TYPE_V6;
}
bool AsyncUDPPacket::isBroadcast()
{
if(_localIp.type == IPADDR_TYPE_V6){
return false;
}
uint32_t ip = _localIp.u_addr.ip4.addr;
return ip == 0xFFFFFFFF || ip == 0 || (ip & 0xFF000000) == 0xFF000000;
}
bool AsyncUDPPacket::isMulticast()
{
return ip_addr_ismulticast(&(_localIp));
}
size_t AsyncUDPPacket::write(const uint8_t *data, size_t len)
{
if(!data){
return 0;
}
return _udp->writeTo(data, len, &_remoteIp, _remotePort, _if);
}
size_t AsyncUDPPacket::write(uint8_t data)
{
return write(&data, 1);
}
size_t AsyncUDPPacket::send(AsyncUDPMessage &message)
{
return write(message.data(), message.length());
}
AsyncUDP::AsyncUDP()
{
_pcb = udp_new();
_connected = false;
_handler = NULL;
if(!_pcb){
return;
}
//_lock = xSemaphoreCreateMutex();
udp_recv(_pcb, &_udp_recv, (void *) this);
}
AsyncUDP::~AsyncUDP()
{
close();
UDP_MUTEX_LOCK();
udp_recv(_pcb, NULL, NULL);
_udp_remove(_pcb);
_pcb = NULL;
UDP_MUTEX_UNLOCK();
//vSemaphoreDelete(_lock);
}
void AsyncUDP::close()
{
UDP_MUTEX_LOCK();
if(_pcb != NULL) {
if(_connected) {
_udp_disconnect(_pcb);
}
_connected = false;
_pcb->multicast_ip.type = IPADDR_TYPE_V4;
_pcb->multicast_ip.u_addr.ip4.addr = 0;
}
UDP_MUTEX_UNLOCK();
}
bool AsyncUDP::connect(const ip_addr_t *addr, uint16_t port)
{
if(!_udp_task_start()){
log_e("failed to start task");
return false;
}
if(_pcb == NULL) {
return false;
}
close();
UDP_MUTEX_LOCK();
err_t err = _udp_connect(_pcb, addr, port);
if(err != ERR_OK) {
UDP_MUTEX_UNLOCK();
return false;
}
_connected = true;
UDP_MUTEX_UNLOCK();
return true;
}
bool AsyncUDP::listen(const ip_addr_t *addr, uint16_t port)
{
if(!_udp_task_start()){
log_e("failed to start task");
return false;
}
if(_pcb == NULL) {
return false;
}
close();
if(addr){
IP_SET_TYPE_VAL(_pcb->local_ip, addr->type);
IP_SET_TYPE_VAL(_pcb->remote_ip, addr->type);
}
UDP_MUTEX_LOCK();
if(_udp_bind(_pcb, addr, port) != ERR_OK) {
UDP_MUTEX_UNLOCK();
return false;
}
_connected = true;
UDP_MUTEX_UNLOCK();
return true;
}
bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if)
{
if(!ip_addr_ismulticast(addr)) {
return false;
}
ip_addr_t multicast_if_addr;
uint8_t mode;
if(esp_wifi_get_mode((wifi_mode_t*)&mode)){
mode = WIFI_MODE_NULL;
}
if(addr->type == IPADDR_TYPE_V6){
multicast_if_addr.type = IPADDR_TYPE_V6;
if((tcpip_if == TCPIP_ADAPTER_IF_STA && (mode & WIFI_MODE_STA))
|| (tcpip_if == TCPIP_ADAPTER_IF_AP && (mode & WIFI_MODE_AP))
|| (tcpip_if == TCPIP_ADAPTER_IF_ETH)) {
if(tcpip_adapter_get_ip6_linklocal(tcpip_if, &multicast_if_addr.u_addr.ip6)){
return false;
}
} else {
return false;
}
if (mld6_joingroup(&(multicast_if_addr.u_addr.ip6), &(addr->u_addr.ip6))) {
return false;
}
} else if(addr->type == IPADDR_TYPE_V4){
tcpip_adapter_ip_info_t ifIpInfo;
if((tcpip_if == TCPIP_ADAPTER_IF_STA && (mode & WIFI_MODE_STA))
|| (tcpip_if == TCPIP_ADAPTER_IF_AP && (mode & WIFI_MODE_AP))
|| (tcpip_if == TCPIP_ADAPTER_IF_ETH)) {
if(tcpip_adapter_get_ip_info(tcpip_if, &ifIpInfo)){
return false;
}
} else {
return false;
}
multicast_if_addr.type = IPADDR_TYPE_V4;
multicast_if_addr.u_addr.ip4.addr = ifIpInfo.ip.addr;
if (igmp_joingroup((const ip4_addr *)&multicast_if_addr.u_addr.ip4, (const ip4_addr *)&addr->u_addr.ip4)!= ERR_OK) {
return false;
}
} else {
return false;
}
if(!listen(&multicast_if_addr, port)) {
return false;
}
UDP_MUTEX_LOCK();
_pcb->mcast_ttl = ttl;
_pcb->remote_port = port;
ip_addr_copy(_pcb->remote_ip, *addr);
if(addr->type == IPADDR_TYPE_V4){
ip_addr_copy(_pcb->multicast_ip, multicast_if_addr);
}
UDP_MUTEX_UNLOCK();
return true;
}
size_t AsyncUDP::writeTo(const uint8_t * data, size_t len, const ip_addr_t * addr, uint16_t port, tcpip_adapter_if_t tcpip_if)
{
if(!_pcb) {
UDP_MUTEX_LOCK();
_pcb = udp_new_ip_type(addr->type);
UDP_MUTEX_UNLOCK();
if(_pcb == NULL) {
return 0;
}
}
if(len > CONFIG_TCP_MSS) {
len = CONFIG_TCP_MSS;
}
err_t err = ERR_OK;
pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
if(pbt != NULL) {
uint8_t* dst = reinterpret_cast<uint8_t*>(pbt->payload);
memcpy(dst, data, len);
UDP_MUTEX_LOCK();
if(tcpip_if != TCPIP_ADAPTER_IF_MAX){
void * nif = NULL;
tcpip_adapter_get_netif((tcpip_adapter_if_t)tcpip_if, &nif);
if(!nif){
err = _udp_sendto(_pcb, pbt, addr, port);
} else {
err = _udp_sendto_if(_pcb, pbt, addr, port, (struct netif *)nif);
}
} else {
err = _udp_sendto(_pcb, pbt, addr, port);
}
UDP_MUTEX_UNLOCK();
pbuf_free(pbt);
if(err < ERR_OK) {
return 0;
}
return len;
}
return 0;
}
void AsyncUDP::_recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif * netif)
{
while(pb != NULL) {
pbuf * this_pb = pb;
pb = pb->next;
this_pb->next = NULL;
if(_handler) {
AsyncUDPPacket packet(this, this_pb, addr, port, netif);
_handler(packet);
} else {
pbuf_free(this_pb);
}
}
}
void AsyncUDP::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port, struct netif * netif)
{
reinterpret_cast<AsyncUDP*>(arg)->_recv(upcb, p, addr, port, netif);
}
bool AsyncUDP::listen(uint16_t port)
{
return listen(IP_ANY_TYPE, port);
}
bool AsyncUDP::listen(const IPAddress addr, uint16_t port)
{
ip_addr_t laddr;
laddr.type = IPADDR_TYPE_V4;
laddr.u_addr.ip4.addr = addr;
return listen(&laddr, port);
}
bool AsyncUDP::listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if)
{
ip_addr_t laddr;
laddr.type = IPADDR_TYPE_V4;
laddr.u_addr.ip4.addr = addr;
return listenMulticast(&laddr, port, ttl, tcpip_if);
}
bool AsyncUDP::connect(const IPAddress addr, uint16_t port)
{
ip_addr_t daddr;
daddr.type = IPADDR_TYPE_V4;
daddr.u_addr.ip4.addr = addr;
return connect(&daddr, port);
}
size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if)
{
ip_addr_t daddr;
daddr.type = IPADDR_TYPE_V4;
daddr.u_addr.ip4.addr = addr;
return writeTo(data, len, &daddr, port, tcpip_if);
}
IPAddress AsyncUDP::listenIP()
{
if(!_pcb || _pcb->remote_ip.type != IPADDR_TYPE_V4){
return IPAddress();
}
return IPAddress(_pcb->remote_ip.u_addr.ip4.addr);
}
bool AsyncUDP::listen(const IPv6Address addr, uint16_t port)
{
ip_addr_t laddr;
laddr.type = IPADDR_TYPE_V6;
memcpy((uint8_t*)(laddr.u_addr.ip6.addr), (const uint8_t*)addr, 16);
return listen(&laddr, port);
}
bool AsyncUDP::listenMulticast(const IPv6Address addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if)
{
ip_addr_t laddr;
laddr.type = IPADDR_TYPE_V6;
memcpy((uint8_t*)(laddr.u_addr.ip6.addr), (const uint8_t*)addr, 16);
return listenMulticast(&laddr, port, ttl, tcpip_if);
}
bool AsyncUDP::connect(const IPv6Address addr, uint16_t port)
{
ip_addr_t daddr;
daddr.type = IPADDR_TYPE_V6;
memcpy((uint8_t*)(daddr.u_addr.ip6.addr), (const uint8_t*)addr, 16);
return connect(&daddr, port);
}
size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if)
{
ip_addr_t daddr;
daddr.type = IPADDR_TYPE_V6;
memcpy((uint8_t*)(daddr.u_addr.ip6.addr), (const uint8_t*)addr, 16);
return writeTo(data, len, &daddr, port, tcpip_if);
}
IPv6Address AsyncUDP::listenIPv6()
{
if(!_pcb || _pcb->remote_ip.type != IPADDR_TYPE_V6){
return IPv6Address();
}
return IPv6Address(_pcb->remote_ip.u_addr.ip6.addr);
}
size_t AsyncUDP::write(const uint8_t *data, size_t len)
{
return writeTo(data, len, &(_pcb->remote_ip), _pcb->remote_port);
}
size_t AsyncUDP::write(uint8_t data)
{
return write(&data, 1);
}
size_t AsyncUDP::broadcastTo(uint8_t *data, size_t len, uint16_t port, tcpip_adapter_if_t tcpip_if)
{
return writeTo(data, len, IP_ADDR_BROADCAST, port, tcpip_if);
}
size_t AsyncUDP::broadcastTo(const char * data, uint16_t port, tcpip_adapter_if_t tcpip_if)
{
return broadcastTo((uint8_t *)data, strlen(data), port, tcpip_if);
}
size_t AsyncUDP::broadcast(uint8_t *data, size_t len)
{
if(_pcb->local_port != 0) {
return broadcastTo(data, len, _pcb->local_port);
}
return 0;
}
size_t AsyncUDP::broadcast(const char * data)
{
return broadcast((uint8_t *)data, strlen(data));
}
size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if)
{
if(!message) {
return 0;
}
return writeTo(message.data(), message.length(), addr, port, tcpip_if);
}
size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if)
{
if(!message) {
return 0;
}
return writeTo(message.data(), message.length(), addr, port, tcpip_if);
}
size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if)
{
if(!message) {
return 0;
}
return writeTo(message.data(), message.length(), addr, port, tcpip_if);
}
size_t AsyncUDP::send(AsyncUDPMessage &message)
{
if(!message) {
return 0;
}
return writeTo(message.data(), message.length(), &(_pcb->remote_ip), _pcb->remote_port);
}
size_t AsyncUDP::broadcastTo(AsyncUDPMessage &message, uint16_t port, tcpip_adapter_if_t tcpip_if)
{
if(!message) {
return 0;
}
return broadcastTo(message.data(), message.length(), port, tcpip_if);
}
size_t AsyncUDP::broadcast(AsyncUDPMessage &message)
{
if(!message) {
return 0;
}
return broadcast(message.data(), message.length());
}
AsyncUDP::operator bool()
{
return _connected;
}
bool AsyncUDP::connected()
{
return _connected;
}
void AsyncUDP::onPacket(AuPacketHandlerFunctionWithArg cb, void * arg)
{
onPacket(std::bind(cb, arg, std::placeholders::_1));
}
void AsyncUDP::onPacket(AuPacketHandlerFunction cb)
{
_handler = cb;
}

View File

@ -0,0 +1,149 @@
#ifndef ESPASYNCUDP_H
#define ESPASYNCUDP_H
#include "IPAddress.h"
#include "IPv6Address.h"
#include "Print.h"
#include <functional>
extern "C" {
#include "lwip/ip_addr.h"
#include <tcpip_adapter.h>
#include "freertos/queue.h"
#include "freertos/semphr.h"
}
class AsyncUDP;
class AsyncUDPPacket;
class AsyncUDPMessage;
struct udp_pcb;
struct pbuf;
struct netif;
typedef std::function<void(AsyncUDPPacket& packet)> AuPacketHandlerFunction;
typedef std::function<void(void * arg, AsyncUDPPacket& packet)> AuPacketHandlerFunctionWithArg;
class AsyncUDPMessage : public Print
{
protected:
uint8_t *_buffer;
size_t _index;
size_t _size;
public:
AsyncUDPMessage(size_t size=CONFIG_TCP_MSS);
virtual ~AsyncUDPMessage();
size_t write(const uint8_t *data, size_t len);
size_t write(uint8_t data);
size_t space();
uint8_t * data();
size_t length();
void flush();
operator bool()
{
return _buffer != NULL;
}
};
class AsyncUDPPacket : public Stream
{
protected:
AsyncUDP *_udp;
pbuf *_pb;
tcpip_adapter_if_t _if;
ip_addr_t _localIp;
uint16_t _localPort;
ip_addr_t _remoteIp;
uint16_t _remotePort;
uint8_t *_data;
size_t _len;
size_t _index;
public:
AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif * netif);
virtual ~AsyncUDPPacket();
uint8_t * data();
size_t length();
bool isBroadcast();
bool isMulticast();
bool isIPv6();
tcpip_adapter_if_t interface();
IPAddress localIP();
IPv6Address localIPv6();
uint16_t localPort();
IPAddress remoteIP();
IPv6Address remoteIPv6();
uint16_t remotePort();
size_t send(AsyncUDPMessage &message);
int available();
size_t read(uint8_t *data, size_t len);
int read();
int peek();
void flush();
size_t write(const uint8_t *data, size_t len);
size_t write(uint8_t data);
};
class AsyncUDP : public Print
{
protected:
udp_pcb *_pcb;
//xSemaphoreHandle _lock;
bool _connected;
AuPacketHandlerFunction _handler;
void _recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif * netif);
public:
AsyncUDP();
virtual ~AsyncUDP();
void onPacket(AuPacketHandlerFunctionWithArg cb, void * arg=NULL);
void onPacket(AuPacketHandlerFunction cb);
bool listen(const ip_addr_t *addr, uint16_t port);
bool listen(const IPAddress addr, uint16_t port);
bool listen(const IPv6Address addr, uint16_t port);
bool listen(uint16_t port);
bool listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_STA);
bool listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_STA);
bool listenMulticast(const IPv6Address addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_STA);
bool connect(const ip_addr_t *addr, uint16_t port);
bool connect(const IPAddress addr, uint16_t port);
bool connect(const IPv6Address addr, uint16_t port);
void close();
size_t writeTo(const uint8_t *data, size_t len, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
size_t writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
size_t writeTo(const uint8_t *data, size_t len, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
size_t write(const uint8_t *data, size_t len);
size_t write(uint8_t data);
size_t broadcastTo(uint8_t *data, size_t len, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
size_t broadcastTo(const char * data, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
size_t broadcast(uint8_t *data, size_t len);
size_t broadcast(const char * data);
size_t sendTo(AsyncUDPMessage &message, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
size_t sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
size_t sendTo(AsyncUDPMessage &message, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
size_t send(AsyncUDPMessage &message);
size_t broadcastTo(AsyncUDPMessage &message, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
size_t broadcast(AsyncUDPMessage &message);
IPAddress listenIP();
IPv6Address listenIPv6();
bool connected();
operator bool();
static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port, struct netif * netif);
};
#endif

View File

@ -40,63 +40,57 @@
#include "esp32-hal-log.h"
#endif
#define SPP_SERVER_NAME "ESP32_SPP_SERVER"
#define SPP_TAG "BluetoothSerial"
const char * _spp_server_name = "ESP32_SPP_SERVER";
#define QUEUE_SIZE 256
uint32_t client;
xQueueHandle SerialQueueBT;
static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_CB;
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_NONE;
static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE;
static uint32_t _spp_client = 0;
static xQueueHandle _spp_queue = NULL;
static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
switch (event)
{
case ESP_SPP_INIT_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
log_i("ESP_SPP_INIT_EVT");
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
esp_spp_start_srv(sec_mask, role_slave, 0, SPP_SERVER_NAME);
esp_spp_start_srv(ESP_SPP_SEC_NONE, ESP_SPP_ROLE_SLAVE, 0, _spp_server_name);
break;
case ESP_SPP_DISCOVERY_COMP_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT");
case ESP_SPP_DISCOVERY_COMP_EVT://discovery complete
log_i("ESP_SPP_DISCOVERY_COMP_EVT");
break;
case ESP_SPP_OPEN_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT");
case ESP_SPP_OPEN_EVT://Client connection open
log_i("ESP_SPP_OPEN_EVT");
break;
case ESP_SPP_CLOSE_EVT:
client = 0;
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
case ESP_SPP_CLOSE_EVT://Client connection closed
_spp_client = 0;
log_i("ESP_SPP_CLOSE_EVT");
break;
case ESP_SPP_START_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
case ESP_SPP_START_EVT://server started
log_i("ESP_SPP_START_EVT");
break;
case ESP_SPP_CL_INIT_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
case ESP_SPP_CL_INIT_EVT://client initiated a connection
log_i("ESP_SPP_CL_INIT_EVT");
break;
case ESP_SPP_DATA_IND_EVT:
ESP_LOGV(SPP_TAG, "ESP_SPP_DATA_IND_EVT len=%d handle=%d", param->data_ind.len, param->data_ind.handle);
case ESP_SPP_DATA_IND_EVT://connection received data
log_v("ESP_SPP_DATA_IND_EVT len=%d handle=%d", param->data_ind.len, param->data_ind.handle);
//esp_log_buffer_hex("",param->data_ind.data,param->data_ind.len); //for low level debug
if (SerialQueueBT != 0){
if (_spp_queue != NULL){
for (int i = 0; i < param->data_ind.len; i++)
xQueueSend(SerialQueueBT, param->data_ind.data + i, (TickType_t)0);
}
else {
ESP_LOGE(SPP_TAG, "SerialQueueBT ERROR");
xQueueSend(_spp_queue, param->data_ind.data + i, (TickType_t)0);
} else {
log_e("SerialQueueBT ERROR");
}
break;
case ESP_SPP_CONG_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CONG_EVT");
case ESP_SPP_CONG_EVT://connection congestion status changed
log_i("ESP_SPP_CONG_EVT");
break;
case ESP_SPP_WRITE_EVT:
ESP_LOGV(SPP_TAG, "ESP_SPP_WRITE_EVT");
case ESP_SPP_WRITE_EVT://write operation completed
log_v("ESP_SPP_WRITE_EVT");
break;
case ESP_SPP_SRV_OPEN_EVT:
client = param->open.handle;
ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
case ESP_SPP_SRV_OPEN_EVT://Server connection open
_spp_client = param->open.handle;
log_i("ESP_SPP_SRV_OPEN_EVT");
break;
default:
break;
@ -106,38 +100,38 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
static bool _init_bt(const char *deviceName)
{
if (!btStarted() && !btStart()){
ESP_LOGE(SPP_TAG, "%s initialize controller failed\n", __func__);
log_e("%s initialize controller failed\n", __func__);
return false;
}
esp_bluedroid_status_t bt_state = esp_bluedroid_get_status();
if (bt_state == ESP_BLUEDROID_STATUS_UNINITIALIZED){
if (esp_bluedroid_init()) {
ESP_LOGE(SPP_TAG, "%s initialize bluedroid failed\n", __func__);
log_e("%s initialize bluedroid failed\n", __func__);
return false;
}
}
if (bt_state != ESP_BLUEDROID_STATUS_ENABLED){
if (esp_bluedroid_enable()) {
ESP_LOGE(SPP_TAG, "%s enable bluedroid failed\n", __func__);
log_e("%s enable bluedroid failed\n", __func__);
return false;
}
}
if (esp_spp_register_callback(esp_spp_cb) != ESP_OK){
ESP_LOGE(SPP_TAG, "%s spp register failed\n", __func__);
log_e("%s spp register failed\n", __func__);
return false;
}
if (esp_spp_init(esp_spp_mode) != ESP_OK){
ESP_LOGE(SPP_TAG, "%s spp init failed\n", __func__);
if (esp_spp_init(ESP_SPP_MODE_CB) != ESP_OK){
log_e("%s spp init failed\n", __func__);
return false;
}
SerialQueueBT = xQueueCreate(QUEUE_SIZE, sizeof(uint8_t)); //initialize the queue
if (SerialQueueBT == NULL){
ESP_LOGE(SPP_TAG, "%s Queue creation error\n", __func__);
_spp_queue = xQueueCreate(QUEUE_SIZE, sizeof(uint8_t)); //initialize the queue
if (_spp_queue == NULL){
log_e("%s Queue creation error\n", __func__);
return false;
}
esp_bt_dev_set_device_name(deviceName);
@ -180,21 +174,21 @@ bool BluetoothSerial::begin(String localName)
int BluetoothSerial::available(void)
{
if (!client || SerialQueueBT == NULL){
if (!_spp_client || _spp_queue == NULL){
return 0;
}
return uxQueueMessagesWaiting(SerialQueueBT);
return uxQueueMessagesWaiting(_spp_queue);
}
int BluetoothSerial::peek(void)
{
if (available()){
if (!client || SerialQueueBT == NULL){
if (!_spp_client || _spp_queue == NULL){
return 0;
}
uint8_t c;
if (xQueuePeek(SerialQueueBT, &c, 0)){
if (xQueuePeek(_spp_queue, &c, 0)){
return c;
}
}
@ -203,7 +197,7 @@ int BluetoothSerial::peek(void)
bool BluetoothSerial::hasClient(void)
{
if (client)
if (_spp_client)
return true;
return false;
@ -212,12 +206,12 @@ bool BluetoothSerial::hasClient(void)
int BluetoothSerial::read(void)
{
if (available()){
if (!client || SerialQueueBT == NULL){
if (!_spp_client || _spp_queue == NULL){
return 0;
}
uint8_t c;
if (xQueueReceive(SerialQueueBT, &c, 0)){
if (xQueueReceive(_spp_queue, &c, 0)){
return c;
}
}
@ -226,10 +220,10 @@ int BluetoothSerial::read(void)
size_t BluetoothSerial::write(uint8_t c)
{
if (client){
if (_spp_client){
uint8_t buffer[1];
buffer[0] = c;
esp_spp_write(client, 1, buffer);
esp_spp_write(_spp_client, 1, buffer);
return 1;
}
return -1;
@ -237,18 +231,18 @@ size_t BluetoothSerial::write(uint8_t c)
size_t BluetoothSerial::write(const uint8_t *buffer, size_t size)
{
if (client){
esp_spp_write(client, size, (uint8_t *)buffer);
if (_spp_client){
esp_spp_write(_spp_client, size, (uint8_t *)buffer);
}
return size;
}
void BluetoothSerial::flush()
{
if (client){
if (_spp_client){
int qsize = available();
uint8_t buffer[qsize];
esp_spp_write(client, qsize, buffer);
esp_spp_write(_spp_client, qsize, buffer);
}
}

View File

@ -29,14 +29,14 @@
#include <esp_log.h>
static const char* TAG = "eeprom";
EEPROMClass::EEPROMClass(uint32_t sector)
: _sector(sector)
, _data(0)
, _size(0)
, _dirty(false)
, _mypart(NULL)
, _name("eeprom")
, _user_defined_size(0)
{
}
@ -45,6 +45,7 @@ EEPROMClass::EEPROMClass(const char* name, uint32_t user_defined_size)
, _data(0)
, _size(0)
, _dirty(false)
, _mypart(NULL)
, _name(name)
, _user_defined_size(user_defined_size)
{
@ -55,7 +56,9 @@ EEPROMClass::EEPROMClass(void)
, _data(0)
, _size(0)
, _dirty(false)
, _mypart(NULL)
, _name("eeprom")
, _user_defined_size(0)
{
}
@ -178,85 +181,85 @@ uint16_t EEPROMClass::length ()
*/
uint8_t EEPROMClass::readByte (int address)
{
uint8_t value;
uint8_t value = 0;
return EEPROMClass::readAll (address, value);
}
int8_t EEPROMClass::readChar (int address)
{
int8_t value;
int8_t value = 0;
return EEPROMClass::readAll (address, value);
}
uint8_t EEPROMClass::readUChar (int address)
{
uint8_t value;
uint8_t value = 0;
return EEPROMClass::readAll (address, value);
}
int16_t EEPROMClass::readShort (int address)
{
int16_t value;
int16_t value = 0;
return EEPROMClass::readAll (address, value);
}
uint16_t EEPROMClass::readUShort (int address)
{
uint16_t value;
uint16_t value = 0;
return EEPROMClass::readAll (address, value);
}
int32_t EEPROMClass::readInt (int address)
{
int32_t value;
int32_t value = 0;
return EEPROMClass::readAll (address, value);
}
uint32_t EEPROMClass::readUInt (int address)
{
uint32_t value;
uint32_t value = 0;
return EEPROMClass::readAll (address, value);
}
int32_t EEPROMClass::readLong (int address)
{
int32_t value;
int32_t value = 0;
return EEPROMClass::readAll (address, value);
}
uint32_t EEPROMClass::readULong (int address)
{
uint32_t value;
uint32_t value = 0;
return EEPROMClass::readAll (address, value);
}
int64_t EEPROMClass::readLong64 (int address)
{
int64_t value;
int64_t value = 0;
return EEPROMClass::readAll (address, value);
}
uint64_t EEPROMClass::readULong64 (int address)
{
uint64_t value;
uint64_t value = 0;
return EEPROMClass::readAll (address, value);
}
float_t EEPROMClass::readFloat (int address)
{
float_t value;
float_t value = 0;
return EEPROMClass::readAll (address, value);
}
double_t EEPROMClass::readDouble (int address)
{
double_t value;
double_t value = 0;
return EEPROMClass::readAll (address, value);
}
bool EEPROMClass::readBool (int address)
{
int8_t value;
int8_t value = 0;
return EEPROMClass::readAll (address, value) ? 1 : 0;
}

View File

@ -0,0 +1,31 @@
#include <WiFi.h>
#include <NetBIOS.h>
const char* ssid = "............";
const char* password = "..............";
void setup() {
Serial.begin(115200);
// Connect to WiFi network
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
NBNS.begin("ESP");
}
void loop() {
}

25
libraries/NetBIOS/keywords.txt Executable file
View File

@ -0,0 +1,25 @@
#######################################
# Syntax Coloring Map For ESPNBNS
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
NetBIOS KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
#######################################
# Instances (KEYWORD2)
#######################################
NBNS KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -0,0 +1,9 @@
name=NetBIOS
version=1.0
author=Pablo@xpablo.cz
maintainer=Hristo Gochkov<hristo@espressif.com>
sentence=Enables NBNS (NetBIOS) name resolution.
paragraph=With this library you can connect to your ESP from Windows using a short name
category=Communication
url=http://www.xpablo.cz/?p=751#more-751
architectures=esp32

131
libraries/NetBIOS/src/NetBIOS.cpp Executable file
View File

@ -0,0 +1,131 @@
#include "NetBIOS.h"
#include <functional>
#define NBNS_PORT 137
#define NBNS_MAX_HOSTNAME_LEN 32
typedef struct {
uint16_t id;
uint8_t flags1;
uint8_t flags2;
uint16_t qcount;
uint16_t acount;
uint16_t nscount;
uint16_t adcount;
uint8_t name_len;
char name[NBNS_MAX_HOSTNAME_LEN + 1];
uint16_t type;
uint16_t clas;
} __attribute__((packed)) nbns_question_t;
typedef struct {
uint16_t id;
uint8_t flags1;
uint8_t flags2;
uint16_t qcount;
uint16_t acount;
uint16_t nscount;
uint16_t adcount;
uint8_t name_len;
char name[NBNS_MAX_HOSTNAME_LEN + 1];
uint16_t type;
uint16_t clas;
uint32_t ttl;
uint16_t data_len;
uint16_t flags;
uint32_t addr;
} __attribute__((packed)) nbns_answer_t;
static void _getnbname(const char *nbname, char *name, uint8_t maxlen){
uint8_t b;
uint8_t c = 0;
while ((*nbname) && (c < maxlen)) {
b = (*nbname++ - 'A') << 4;
c++;
if (*nbname) {
b |= *nbname++ - 'A';
c++;
}
if(!b || b == ' '){
break;
}
*name++ = b;
}
*name = 0;
}
static void append_16(void * dst, uint16_t value){
uint8_t * d = (uint8_t *)dst;
*d++ = (value >> 8) & 0xFF;
*d++ = value & 0xFF;
}
static void append_32(void * dst, uint32_t value){
uint8_t * d = (uint8_t *)dst;
*d++ = (value >> 24) & 0xFF;
*d++ = (value >> 16) & 0xFF;
*d++ = (value >> 8) & 0xFF;
*d++ = value & 0xFF;
}
void NetBIOS::_onPacket(AsyncUDPPacket& packet){
if (packet.length() >= sizeof(nbns_question_t)) {
nbns_question_t * question = (nbns_question_t *)packet.data();
if (0 == (question->flags1 & 0x80)) {
char name[ NBNS_MAX_HOSTNAME_LEN + 1 ];
_getnbname(&question->name[0], (char *)&name, question->name_len);
if (_name.equals(name)) {
nbns_answer_t nbnsa;
nbnsa.id = question->id;
nbnsa.flags1 = 0x85;
nbnsa.flags2 = 0;
append_16((void *)&nbnsa.qcount, 0);
append_16((void *)&nbnsa.acount, 1);
append_16((void *)&nbnsa.nscount, 0);
append_16((void *)&nbnsa.adcount, 0);
nbnsa.name_len = question->name_len;
memcpy(&nbnsa.name[0], &question->name[0], question->name_len + 1);
append_16((void *)&nbnsa.type, 0x20);
append_16((void *)&nbnsa.clas, 1);
append_32((void *)&nbnsa.ttl, 300000);
append_16((void *)&nbnsa.data_len, 6);
append_16((void *)&nbnsa.flags, 0);
nbnsa.addr = WiFi.localIP();
_udp.writeTo((uint8_t *)&nbnsa, sizeof(nbnsa), packet.remoteIP(), NBNS_PORT);
}
}
}
}
NetBIOS::NetBIOS(){
}
NetBIOS::~NetBIOS(){
end();
}
bool NetBIOS::begin(const char *name){
_name = name;
_name.toUpperCase();
if(_udp.connected()){
return true;
}
_udp.onPacket([](void * arg, AsyncUDPPacket& packet){ ((NetBIOS*)(arg))->_onPacket(packet); }, this);
return _udp.listen(NBNS_PORT);
}
void NetBIOS::end(){
if(_udp.connected()){
_udp.close();
}
}
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_NETBIOS)
NetBIOS NBNS;
#endif
// EOF

26
libraries/NetBIOS/src/NetBIOS.h Executable file
View File

@ -0,0 +1,26 @@
//
#ifndef __ESPNBNS_h__
#define __ESPNBNS_h__
#include <WiFi.h>
#include "AsyncUDP.h"
class NetBIOS
{
protected:
AsyncUDP _udp;
String _name;
void _onPacket(AsyncUDPPacket& packet);
public:
NetBIOS();
~NetBIOS();
bool begin(const char *name);
void end();
};
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_NETBIOS)
extern NetBIOS NBNS;
#endif
#endif

View File

@ -42,7 +42,21 @@ bool SDMMCFS::begin(const char * mountpoint, bool mode1bit)
}
//mount
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
sdmmc_host_t host = {
.flags = SDMMC_HOST_FLAG_4BIT,
.slot = SDMMC_HOST_SLOT_1,
.max_freq_khz = SDMMC_FREQ_DEFAULT,
.io_voltage = 3.3f,
.init = &sdmmc_host_init,
.set_bus_width = &sdmmc_host_set_bus_width,
.get_bus_width = &sdmmc_host_get_slot_width,
.set_card_clk = &sdmmc_host_set_card_clk,
.do_transaction = &sdmmc_host_do_transaction,
.deinit = &sdmmc_host_deinit,
.io_int_enable = sdmmc_host_io_int_enable,
.io_int_wait = sdmmc_host_io_int_wait,
.command_timeout_ms = 0,
};
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
#ifdef BOARD_HAS_1BIT_SDMMC
mode1bit = true;
@ -53,7 +67,8 @@ bool SDMMCFS::begin(const char * mountpoint, bool mode1bit)
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = 5
.max_files = 5,
.allocation_unit_size = 0
};
esp_err_t ret = esp_vfs_fat_sdmmc_mount(mountpoint, &host, &slot_config, &mount_config, &_card);

View File

@ -19,8 +19,7 @@
#include "SimpleBLE.h"
#include "esp32-hal-log.h"
#include "bt.h"
#include "bta_api.h"
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"

View File

@ -25,7 +25,7 @@
#include <cstring>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "bt.h"
#include "esp_bt.h"
#include "Arduino.h"

View File

@ -0,0 +1,146 @@
/*
Copyright (c) 2015, Majenko Technologies
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* * Neither the name of Majenko Technologies nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
const char *ssid = "YourSSIDHere";
const char *password = "YourPSKHere";
WebServer server(80);
const int led = 13;
void handleRoot() {
digitalWrite(led, 1);
char temp[400];
int sec = millis() / 1000;
int min = sec / 60;
int hr = min / 60;
snprintf(temp, 400,
"<html>\
<head>\
<meta http-equiv='refresh' content='5'/>\
<title>ESP32 Demo</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<h1>Hello from ESP32!</h1>\
<p>Uptime: %02d:%02d:%02d</p>\
<img src=\"/test.svg\" />\
</body>\
</html>",
hr, min % 60, sec % 60
);
server.send(200, "text/html", temp);
digitalWrite(led, 0);
}
void handleNotFound() {
digitalWrite(led, 1);
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
digitalWrite(led, 0);
}
void setup(void) {
pinMode(led, OUTPUT);
digitalWrite(led, 0);
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (MDNS.begin("esp32")) {
Serial.println("MDNS responder started");
}
server.on("/", handleRoot);
server.on("/test.svg", drawGraph);
server.on("/inline", []() {
server.send(200, "text/plain", "this works as well");
});
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop(void) {
server.handleClient();
}
void drawGraph() {
String out = "";
char temp[100];
out += "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"400\" height=\"150\">\n";
out += "<rect width=\"400\" height=\"150\" fill=\"rgb(250, 230, 210)\" stroke-width=\"1\" stroke=\"rgb(0, 0, 0)\" />\n";
out += "<g stroke=\"black\">\n";
int y = rand() % 130;
for (int x = 10; x < 390; x += 10) {
int y2 = rand() % 130;
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", x, 140 - y, x + 10, 140 - y2);
out += temp;
y = y2;
}
out += "</g>\n</svg>\n";
server.send(200, "image/svg+xml", out);
}

View File

@ -0,0 +1,294 @@
/*
FSWebServer - Example WebServer with SPIFFS backend for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the WebServer library for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
upload the contents of the data folder with MkSPIFFS Tool ("ESP32 Sketch Data Upload" in Tools menu in Arduino IDE)
or you can upload the contents of a folder if you CD in that folder and run the following command:
for file in `ls -A1`; do curl -F "file=@$PWD/$file" esp32fs.local/edit; done
access the sample web page at http://esp32fs.local
edit the page by going to http://esp32fs.local/edit
*/
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <SPIFFS.h>
#define DBG_OUTPUT_PORT Serial
const char* ssid = "wifi-ssid";
const char* password = "wifi-password";
const char* host = "esp32fs";
WebServer server(80);
//holds the current upload
File fsUploadFile;
//format bytes
String formatBytes(size_t bytes) {
if (bytes < 1024) {
return String(bytes) + "B";
} else if (bytes < (1024 * 1024)) {
return String(bytes / 1024.0) + "KB";
} else if (bytes < (1024 * 1024 * 1024)) {
return String(bytes / 1024.0 / 1024.0) + "MB";
} else {
return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB";
}
}
String getContentType(String filename) {
if (server.hasArg("download")) {
return "application/octet-stream";
} else if (filename.endsWith(".htm")) {
return "text/html";
} else if (filename.endsWith(".html")) {
return "text/html";
} else if (filename.endsWith(".css")) {
return "text/css";
} else if (filename.endsWith(".js")) {
return "application/javascript";
} else if (filename.endsWith(".png")) {
return "image/png";
} else if (filename.endsWith(".gif")) {
return "image/gif";
} else if (filename.endsWith(".jpg")) {
return "image/jpeg";
} else if (filename.endsWith(".ico")) {
return "image/x-icon";
} else if (filename.endsWith(".xml")) {
return "text/xml";
} else if (filename.endsWith(".pdf")) {
return "application/x-pdf";
} else if (filename.endsWith(".zip")) {
return "application/x-zip";
} else if (filename.endsWith(".gz")) {
return "application/x-gzip";
}
return "text/plain";
}
bool exists(String path){
bool yes = false;
File file = SPIFFS.open(path, "r");
if(!file.isDirectory()){
yes = true;
}
file.close();
return yes;
}
bool handleFileRead(String path) {
DBG_OUTPUT_PORT.println("handleFileRead: " + path);
if (path.endsWith("/")) {
path += "index.htm";
}
String contentType = getContentType(path);
String pathWithGz = path + ".gz";
if (exists(pathWithGz) || exists(path)) {
if (exists(pathWithGz)) {
path += ".gz";
}
File file = SPIFFS.open(path, "r");
server.streamFile(file, contentType);
file.close();
return true;
}
return false;
}
void handleFileUpload() {
if (server.uri() != "/edit") {
return;
}
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
String filename = upload.filename;
if (!filename.startsWith("/")) {
filename = "/" + filename;
}
DBG_OUTPUT_PORT.print("handleFileUpload Name: "); DBG_OUTPUT_PORT.println(filename);
fsUploadFile = SPIFFS.open(filename, "w");
filename = String();
} else if (upload.status == UPLOAD_FILE_WRITE) {
//DBG_OUTPUT_PORT.print("handleFileUpload Data: "); DBG_OUTPUT_PORT.println(upload.currentSize);
if (fsUploadFile) {
fsUploadFile.write(upload.buf, upload.currentSize);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (fsUploadFile) {
fsUploadFile.close();
}
DBG_OUTPUT_PORT.print("handleFileUpload Size: "); DBG_OUTPUT_PORT.println(upload.totalSize);
}
}
void handleFileDelete() {
if (server.args() == 0) {
return server.send(500, "text/plain", "BAD ARGS");
}
String path = server.arg(0);
DBG_OUTPUT_PORT.println("handleFileDelete: " + path);
if (path == "/") {
return server.send(500, "text/plain", "BAD PATH");
}
if (!exists(path)) {
return server.send(404, "text/plain", "FileNotFound");
}
SPIFFS.remove(path);
server.send(200, "text/plain", "");
path = String();
}
void handleFileCreate() {
if (server.args() == 0) {
return server.send(500, "text/plain", "BAD ARGS");
}
String path = server.arg(0);
DBG_OUTPUT_PORT.println("handleFileCreate: " + path);
if (path == "/") {
return server.send(500, "text/plain", "BAD PATH");
}
if (exists(path)) {
return server.send(500, "text/plain", "FILE EXISTS");
}
File file = SPIFFS.open(path, "w");
if (file) {
file.close();
} else {
return server.send(500, "text/plain", "CREATE FAILED");
}
server.send(200, "text/plain", "");
path = String();
}
void handleFileList() {
if (!server.hasArg("dir")) {
server.send(500, "text/plain", "BAD ARGS");
return;
}
String path = server.arg("dir");
DBG_OUTPUT_PORT.println("handleFileList: " + path);
File root = SPIFFS.open(path);
path = String();
String output = "[";
if(root.isDirectory()){
File file = root.openNextFile();
while(file){
if (output != "[") {
output += ',';
}
output += "{\"type\":\"";
output += (file.isDirectory()) ? "dir" : "file";
output += "\",\"name\":\"";
output += String(file.name()).substring(1);
output += "\"}";
file = root.openNextFile();
}
}
output += "]";
server.send(200, "text/json", output);
}
void setup(void) {
DBG_OUTPUT_PORT.begin(115200);
DBG_OUTPUT_PORT.print("\n");
DBG_OUTPUT_PORT.setDebugOutput(true);
SPIFFS.begin();
{
File root = SPIFFS.open("/");
File file = root.openNextFile();
while(file){
String fileName = file.name();
size_t fileSize = file.size();
DBG_OUTPUT_PORT.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str());
file = root.openNextFile();
}
DBG_OUTPUT_PORT.printf("\n");
}
//WIFI INIT
DBG_OUTPUT_PORT.printf("Connecting to %s\n", ssid);
if (String(WiFi.SSID()) != String(ssid)) {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
}
while (WiFi.status() != WL_CONNECTED) {
delay(500);
DBG_OUTPUT_PORT.print(".");
}
DBG_OUTPUT_PORT.println("");
DBG_OUTPUT_PORT.print("Connected! IP address: ");
DBG_OUTPUT_PORT.println(WiFi.localIP());
MDNS.begin(host);
DBG_OUTPUT_PORT.print("Open http://");
DBG_OUTPUT_PORT.print(host);
DBG_OUTPUT_PORT.println(".local/edit to see the file browser");
//SERVER INIT
//list directory
server.on("/list", HTTP_GET, handleFileList);
//load editor
server.on("/edit", HTTP_GET, []() {
if (!handleFileRead("/edit.htm")) {
server.send(404, "text/plain", "FileNotFound");
}
});
//create file
server.on("/edit", HTTP_PUT, handleFileCreate);
//delete file
server.on("/edit", HTTP_DELETE, handleFileDelete);
//first callback is called after the request has ended with all parsed arguments
//second callback handles file uploads at that location
server.on("/edit", HTTP_POST, []() {
server.send(200, "text/plain", "");
}, handleFileUpload);
//called when the url is not defined here
//use it to load content from SPIFFS
server.onNotFound([]() {
if (!handleFileRead(server.uri())) {
server.send(404, "text/plain", "FileNotFound");
}
});
//get heap status, analog input value and all GPIO statuses in one json call
server.on("/all", HTTP_GET, []() {
String json = "{";
json += "\"heap\":" + String(ESP.getFreeHeap());
json += ", \"analog\":" + String(analogRead(A0));
json += ", \"gpio\":" + String((uint32_t)(0));
json += "}";
server.send(200, "text/json", json);
json = String();
});
server.begin();
DBG_OUTPUT_PORT.println("HTTP server started");
}
void loop(void) {
server.handleClient();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,97 @@
<!--
FSWebServer - Example Index Page
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the WebServer library for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>ESP Monitor</title>
<script type="text/javascript" src="graphs.js"></script>
<script type="text/javascript">
var heap,temp,digi;
var reloadPeriod = 1000;
var running = false;
function loadValues(){
if(!running) return;
var xh = new XMLHttpRequest();
xh.onreadystatechange = function(){
if (xh.readyState == 4){
if(xh.status == 200) {
var res = JSON.parse(xh.responseText);
heap.add(res.heap);
temp.add(res.analog);
digi.add(res.gpio);
if(running) setTimeout(loadValues, reloadPeriod);
} else running = false;
}
};
xh.open("GET", "/all", true);
xh.send(null);
};
function run(){
if(!running){
running = true;
loadValues();
}
}
function onBodyLoad(){
var refreshInput = document.getElementById("refresh-rate");
refreshInput.value = reloadPeriod;
refreshInput.onchange = function(e){
var value = parseInt(e.target.value);
reloadPeriod = (value > 0)?value:0;
e.target.value = reloadPeriod;
}
var stopButton = document.getElementById("stop-button");
stopButton.onclick = function(e){
running = false;
}
var startButton = document.getElementById("start-button");
startButton.onclick = function(e){
run();
}
// Example with 10K thermistor
//function calcThermistor(v) {
// var t = Math.log(((10230000 / v) - 10000));
// t = (1/(0.001129148+(0.000234125*t)+(0.0000000876741*t*t*t)))-273.15;
// return (t>120)?0:Math.round(t*10)/10;
//}
//temp = createGraph(document.getElementById("analog"), "Temperature", 100, 128, 10, 40, false, "cyan", calcThermistor);
temp = createGraph(document.getElementById("analog"), "Analog Input", 100, 128, 0, 1023, false, "cyan");
heap = createGraph(document.getElementById("heap"), "Current Heap", 100, 125, 0, 30000, true, "orange");
digi = createDigiGraph(document.getElementById("digital"), "GPIO", 100, 146, [0, 4, 5, 16], "gold");
run();
}
</script>
</head>
<body id="index" style="margin:0; padding:0;" onload="onBodyLoad()">
<div id="controls" style="display: block; border: 1px solid rgb(68, 68, 68); padding: 5px; margin: 5px; width: 362px; background-color: rgb(238, 238, 238);">
<label>Period (ms):</label>
<input type="number" id="refresh-rate"/>
<input type="button" id="start-button" value="Start"/>
<input type="button" id="stop-button" value="Stop"/>
</div>
<div id="heap"></div>
<div id="analog"></div>
<div id="digital"></div>
</body>
</html>

View File

@ -0,0 +1,73 @@
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
const char* ssid = "........";
const char* password = "........";
WebServer server(80);
const int led = 13;
void handleRoot() {
digitalWrite(led, 1);
server.send(200, "text/plain", "hello from esp8266!");
digitalWrite(led, 0);
}
void handleNotFound() {
digitalWrite(led, 1);
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
digitalWrite(led, 0);
}
void setup(void) {
pinMode(led, OUTPUT);
digitalWrite(led, 0);
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (MDNS.begin("esp32")) {
Serial.println("MDNS responder started");
}
server.on("/", handleRoot);
server.on("/inline", []() {
server.send(200, "text/plain", "this works as well");
});
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop(void) {
server.handleClient();
}

View File

@ -0,0 +1,59 @@
/*
HTTP Advanced Authentication example
Created Mar 16, 2017 by Ahmed El-Sharnoby.
This example code is in the public domain.
*/
#include <WiFi.h>
#include <ESPmDNS.h>
#include <ArduinoOTA.h>
#include <WebServer.h>
const char* ssid = "........";
const char* password = "........";
WebServer server(80);
const char* www_username = "admin";
const char* www_password = "esp32";
// allows you to set the realm of authentication Default:"Login Required"
const char* www_realm = "Custom Auth Realm";
// the Content of the HTML response in case of Unautherized Access Default:empty
String authFailResponse = "Authentication Failed";
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Connect Failed! Rebooting...");
delay(1000);
ESP.restart();
}
ArduinoOTA.begin();
server.on("/", []() {
if (!server.authenticate(www_username, www_password))
//Basic Auth Method with Custom realm and Failure Response
//return server.requestAuthentication(BASIC_AUTH, www_realm, authFailResponse);
//Digest Auth Method with realm="Login Required" and empty Failure Response
//return server.requestAuthentication(DIGEST_AUTH);
//Digest Auth Method with Custom realm and empty Failure Response
//return server.requestAuthentication(DIGEST_AUTH, www_realm);
//Digest Auth Method with Custom realm and Failure Response
{
return server.requestAuthentication(DIGEST_AUTH, www_realm, authFailResponse);
}
server.send(200, "text/plain", "Login OK");
});
server.begin();
Serial.print("Open http://");
Serial.print(WiFi.localIP());
Serial.println("/ in your browser to see it working");
}
void loop() {
ArduinoOTA.handle();
server.handleClient();
}

View File

@ -0,0 +1,41 @@
#include <WiFi.h>
#include <ESPmDNS.h>
#include <ArduinoOTA.h>
#include <WebServer.h>
const char* ssid = "........";
const char* password = "........";
WebServer server(80);
const char* www_username = "admin";
const char* www_password = "esp32";
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Connect Failed! Rebooting...");
delay(1000);
ESP.restart();
}
ArduinoOTA.begin();
server.on("/", []() {
if (!server.authenticate(www_username, www_password)) {
return server.requestAuthentication();
}
server.send(200, "text/plain", "Login OK");
});
server.begin();
Serial.print("Open http://");
Serial.print(WiFi.localIP());
Serial.println("/ in your browser to see it working");
}
void loop() {
ArduinoOTA.handle();
server.handleClient();
}

View File

@ -0,0 +1,313 @@
/*
SDWebServer - Example WebServer with SD Card backend for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the WebServer library for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Have a FAT Formatted SD Card connected to the SPI port of the ESP8266
The web root is the SD Card root folder
File extensions with more than 3 charecters are not supported by the SD Library
File Names longer than 8 charecters will be truncated by the SD library, so keep filenames shorter
index.htm is the default index (works on subfolders as well)
upload the contents of SdRoot to the root of the SDcard and access the editor by going to http://esp8266sd.local/edit
*/
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <SPI.h>
#include <SD.h>
#define DBG_OUTPUT_PORT Serial
const char* ssid = "**********";
const char* password = "**********";
const char* host = "esp32sd";
WebServer server(80);
static bool hasSD = false;
File uploadFile;
void returnOK() {
server.send(200, "text/plain", "");
}
void returnFail(String msg) {
server.send(500, "text/plain", msg + "\r\n");
}
bool loadFromSdCard(String path) {
String dataType = "text/plain";
if (path.endsWith("/")) {
path += "index.htm";
}
if (path.endsWith(".src")) {
path = path.substring(0, path.lastIndexOf("."));
} else if (path.endsWith(".htm")) {
dataType = "text/html";
} else if (path.endsWith(".css")) {
dataType = "text/css";
} else if (path.endsWith(".js")) {
dataType = "application/javascript";
} else if (path.endsWith(".png")) {
dataType = "image/png";
} else if (path.endsWith(".gif")) {
dataType = "image/gif";
} else if (path.endsWith(".jpg")) {
dataType = "image/jpeg";
} else if (path.endsWith(".ico")) {
dataType = "image/x-icon";
} else if (path.endsWith(".xml")) {
dataType = "text/xml";
} else if (path.endsWith(".pdf")) {
dataType = "application/pdf";
} else if (path.endsWith(".zip")) {
dataType = "application/zip";
}
File dataFile = SD.open(path.c_str());
if (dataFile.isDirectory()) {
path += "/index.htm";
dataType = "text/html";
dataFile = SD.open(path.c_str());
}
if (!dataFile) {
return false;
}
if (server.hasArg("download")) {
dataType = "application/octet-stream";
}
if (server.streamFile(dataFile, dataType) != dataFile.size()) {
DBG_OUTPUT_PORT.println("Sent less data than expected!");
}
dataFile.close();
return true;
}
void handleFileUpload() {
if (server.uri() != "/edit") {
return;
}
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
if (SD.exists((char *)upload.filename.c_str())) {
SD.remove((char *)upload.filename.c_str());
}
uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE);
DBG_OUTPUT_PORT.print("Upload: START, filename: "); DBG_OUTPUT_PORT.println(upload.filename);
} else if (upload.status == UPLOAD_FILE_WRITE) {
if (uploadFile) {
uploadFile.write(upload.buf, upload.currentSize);
}
DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: "); DBG_OUTPUT_PORT.println(upload.currentSize);
} else if (upload.status == UPLOAD_FILE_END) {
if (uploadFile) {
uploadFile.close();
}
DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.totalSize);
}
}
void deleteRecursive(String path) {
File file = SD.open((char *)path.c_str());
if (!file.isDirectory()) {
file.close();
SD.remove((char *)path.c_str());
return;
}
file.rewindDirectory();
while (true) {
File entry = file.openNextFile();
if (!entry) {
break;
}
String entryPath = path + "/" + entry.name();
if (entry.isDirectory()) {
entry.close();
deleteRecursive(entryPath);
} else {
entry.close();
SD.remove((char *)entryPath.c_str());
}
yield();
}
SD.rmdir((char *)path.c_str());
file.close();
}
void handleDelete() {
if (server.args() == 0) {
return returnFail("BAD ARGS");
}
String path = server.arg(0);
if (path == "/" || !SD.exists((char *)path.c_str())) {
returnFail("BAD PATH");
return;
}
deleteRecursive(path);
returnOK();
}
void handleCreate() {
if (server.args() == 0) {
return returnFail("BAD ARGS");
}
String path = server.arg(0);
if (path == "/" || SD.exists((char *)path.c_str())) {
returnFail("BAD PATH");
return;
}
if (path.indexOf('.') > 0) {
File file = SD.open((char *)path.c_str(), FILE_WRITE);
if (file) {
file.write(0);
file.close();
}
} else {
SD.mkdir((char *)path.c_str());
}
returnOK();
}
void printDirectory() {
if (!server.hasArg("dir")) {
return returnFail("BAD ARGS");
}
String path = server.arg("dir");
if (path != "/" && !SD.exists((char *)path.c_str())) {
return returnFail("BAD PATH");
}
File dir = SD.open((char *)path.c_str());
path = String();
if (!dir.isDirectory()) {
dir.close();
return returnFail("NOT DIR");
}
dir.rewindDirectory();
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
server.send(200, "text/json", "");
WiFiClient client = server.client();
server.sendContent("[");
for (int cnt = 0; true; ++cnt) {
File entry = dir.openNextFile();
if (!entry) {
break;
}
String output;
if (cnt > 0) {
output = ',';
}
output += "{\"type\":\"";
output += (entry.isDirectory()) ? "dir" : "file";
output += "\",\"name\":\"";
output += entry.name();
output += "\"";
output += "}";
server.sendContent(output);
entry.close();
}
server.sendContent("]");
dir.close();
}
void handleNotFound() {
if (hasSD && loadFromSdCard(server.uri())) {
return;
}
String message = "SDCARD Not Detected\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " NAME:" + server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
DBG_OUTPUT_PORT.print(message);
}
void setup(void) {
DBG_OUTPUT_PORT.begin(115200);
DBG_OUTPUT_PORT.setDebugOutput(true);
DBG_OUTPUT_PORT.print("\n");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
DBG_OUTPUT_PORT.print("Connecting to ");
DBG_OUTPUT_PORT.println(ssid);
// Wait for connection
uint8_t i = 0;
while (WiFi.status() != WL_CONNECTED && i++ < 20) {//wait 10 seconds
delay(500);
}
if (i == 21) {
DBG_OUTPUT_PORT.print("Could not connect to");
DBG_OUTPUT_PORT.println(ssid);
while (1) {
delay(500);
}
}
DBG_OUTPUT_PORT.print("Connected! IP address: ");
DBG_OUTPUT_PORT.println(WiFi.localIP());
if (MDNS.begin(host)) {
MDNS.addService("http", "tcp", 80);
DBG_OUTPUT_PORT.println("MDNS responder started");
DBG_OUTPUT_PORT.print("You can now connect to http://");
DBG_OUTPUT_PORT.print(host);
DBG_OUTPUT_PORT.println(".local");
}
server.on("/list", HTTP_GET, printDirectory);
server.on("/edit", HTTP_DELETE, handleDelete);
server.on("/edit", HTTP_PUT, handleCreate);
server.on("/edit", HTTP_POST, []() {
returnOK();
}, handleFileUpload);
server.onNotFound(handleNotFound);
server.begin();
DBG_OUTPUT_PORT.println("HTTP server started");
if (SD.begin(SS)) {
DBG_OUTPUT_PORT.println("SD Card initialized.");
hasSD = true;
}
}
void loop(void) {
server.handleClient();
}

View File

@ -0,0 +1,674 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SD Editor</title>
<style type="text/css" media="screen">
.contextMenu {
z-index: 300;
position: absolute;
left: 5px;
border: 1px solid #444;
background-color: #F5F5F5;
display: none;
box-shadow: 0 0 10px rgba( 0, 0, 0, .4 );
font-size: 12px;
font-family: sans-serif;
font-weight:bold;
}
.contextMenu ul {
list-style: none;
top: 0;
left: 0;
margin: 0;
padding: 0;
}
.contextMenu li {
position: relative;
min-width: 60px;
cursor: pointer;
}
.contextMenu span {
color: #444;
display: inline-block;
padding: 6px;
}
.contextMenu li:hover { background: #444; }
.contextMenu li:hover span { color: #EEE; }
.css-treeview ul, .css-treeview li {
padding: 0;
margin: 0;
list-style: none;
}
.css-treeview input {
position: absolute;
opacity: 0;
}
.css-treeview {
font: normal 11px Verdana, Arial, Sans-serif;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
}
.css-treeview span {
color: #00f;
cursor: pointer;
}
.css-treeview span:hover {
text-decoration: underline;
}
.css-treeview input + label + ul {
margin: 0 0 0 22px;
}
.css-treeview input ~ ul {
display: none;
}
.css-treeview label, .css-treeview label::before {
cursor: pointer;
}
.css-treeview input:disabled + label {
cursor: default;
opacity: .6;
}
.css-treeview input:checked:not(:disabled) ~ ul {
display: block;
}
.css-treeview label, .css-treeview label::before {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAACgCAYAAAAFOewUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAApxJREFUeNrslM1u00AQgGdthyalFFOK+ClIIKQKyqUVQvTEE3DmAhLwAhU8QZoH4A2Q2gMSFace4MCtJ8SPBFwAkRuiHKpA6sRN/Lu7zG5i14kctaUqRGhGXnu9O/Pt7MzsMiklvF+9t2kWTDvyIrAsA0aKRRi1T0C/hJ4LUbt5/8rNpWVlp8RSr9J40b48fxFaTQ9+ft8EZ6MJYb0Ok+dnYGpmPgXwKIAvLx8vYXc5GdMAQJgQEkpjRTh36TS2U+DWW/D17WuYgm8pwJyY1npZsZKOxImOV1I/h4+O6vEg5GCZBpgmA6hX8wHKUHDRBXQYicQ4rlc3Tf0VMs8DHBS864F2YFspjgUYjKX/Az3gsdQd2eeBHwmdGWXHcgBGSkZXOXohcEXebRoQcAgjqediNY+AVyu3Z3sAKqfKoGMsewBeEIOPgQxxPJIjcGH6qtL/0AdADzKGnuuD+2tLK7Q8DhHHbOBW+KEzcHLuYc82MkEUekLiwuvVH+guQBQzOG4XdAb8EOcRcqQvDkY2iCLuxECJ43JobMXoutqGgDa2T7UqLKwt9KRyuxKVByqVXXqIoCCUCAqhUOioTWC7G4TQEOD0APy2/7G2Xpu1J4+lxeQ4TXBbITDpoVelRN/BVFbwu5oMMJUBhoXy5tmdRcMwymP2OLQaLjx9/vnBo6V3K6izATmSnMa0Dq7ferIohJhr1p01zrlz49rZF4OMs8JkX23vVQzYp+wbYGV/KpXKjvspl8tsIKCrMNAYFxj2GKS5ZWxg4ewKsJfaGMIY5KXqPz8LBBj6+yDvVP79+yDp/9F9oIx3OisHWwe7Oal0HxCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgwD8E/BZgAP0qhKj3rXO7AAAAAElFTkSuQmCC") no-repeat;
}
.css-treeview label, .css-treeview span, .css-treeview label::before {
display: inline-block;
height: 16px;
line-height: 16px;
vertical-align: middle;
}
.css-treeview label {
background-position: 18px 0;
}
.css-treeview label::before {
content: "";
width: 16px;
margin: 0 22px 0 0;
vertical-align: middle;
background-position: 0 -32px;
}
.css-treeview input:checked + label::before {
background-position: 0 -16px;
}
/* webkit adjacent element selector bugfix */
@media screen and (-webkit-min-device-pixel-ratio:0)
{
.css-treeview{
-webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s;
}
@-webkit-keyframes webkit-adjacent-element-selector-bugfix
{
from {
padding: 0;
}
to {
padding: 0;
}
}
}
#uploader {
position: absolute;
top: 0;
right: 0;
left: 0;
height:28px;
line-height: 24px;
padding-left: 10px;
background-color: #444;
color:#EEE;
}
#tree {
position: absolute;
top: 28px;
bottom: 0;
left: 0;
width:200px;
padding: 8px;
}
#editor, #preview {
position: absolute;
top: 28px;
right: 0;
bottom: 0;
left: 200px;
}
#preview {
background-color: #EEE;
padding:5px;
}
</style>
<script>
function createFileUploader(element, tree, editor){
var xmlHttp;
var input = document.createElement("input");
input.type = "file";
input.multiple = false;
input.name = "data";
document.getElementById(element).appendChild(input);
var path = document.createElement("input");
path.id = "upload-path";
path.type = "text";
path.name = "path";
path.defaultValue = "/";
document.getElementById(element).appendChild(path);
var button = document.createElement("button");
button.innerHTML = 'Upload';
document.getElementById(element).appendChild(button);
var mkdir = document.createElement("button");
mkdir.innerHTML = 'MkDir';
document.getElementById(element).appendChild(mkdir);
var mkfile = document.createElement("button");
mkfile.innerHTML = 'MkFile';
document.getElementById(element).appendChild(mkfile);
function httpPostProcessRequest(){
if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
else {
tree.refreshPath(path.value);
}
}
}
function createPath(p){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpPostProcessRequest;
var formData = new FormData();
formData.append("path", p);
xmlHttp.open("PUT", "/edit");
xmlHttp.send(formData);
}
mkfile.onclick = function(e){
if(path.value.indexOf(".") === -1) return;
createPath(path.value);
editor.loadUrl(path.value);
};
mkdir.onclick = function(e){
if(path.value.length < 2) return;
var dir = path.value
if(dir.indexOf(".") !== -1){
if(dir.lastIndexOf("/") === 0) return;
dir = dir.substring(0, dir.lastIndexOf("/"));
}
createPath(dir);
};
button.onclick = function(e){
if(input.files.length === 0){
return;
}
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpPostProcessRequest;
var formData = new FormData();
formData.append("data", input.files[0], path.value);
xmlHttp.open("POST", "/edit");
xmlHttp.send(formData);
}
input.onchange = function(e){
if(input.files.length === 0) return;
var filename = input.files[0].name;
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
var name = /(.*)\.[^.]+$/.exec(filename)[1];
if(typeof name !== undefined){
if(name.length > 8) name = name.substring(0, 8);
filename = name;
}
if(typeof ext !== undefined){
if(ext === "html") ext = "htm";
else if(ext === "jpeg") ext = "jpg";
filename = filename + "." + ext;
}
if(path.value === "/" || path.value.lastIndexOf("/") === 0){
path.value = "/"+filename;
} else {
path.value = path.value.substring(0, path.value.lastIndexOf("/")+1)+filename;
}
}
}
function createTree(element, editor){
var preview = document.getElementById("preview");
var treeRoot = document.createElement("div");
treeRoot.className = "css-treeview";
document.getElementById(element).appendChild(treeRoot);
function loadDownload(path){
document.getElementById('download-frame').src = path+"?download=true";
}
function loadPreview(path){
document.getElementById("editor").style.display = "none";
preview.style.display = "block";
preview.innerHTML = '<img src="'+path+'" style="max-width:100%; max-height:100%; margin:auto; display:block;" />';
}
function fillFolderMenu(el, path){
var list = document.createElement("ul");
el.appendChild(list);
var action = document.createElement("li");
list.appendChild(action);
var isChecked = document.getElementById(path).checked;
var expnd = document.createElement("li");
list.appendChild(expnd);
if(isChecked){
expnd.innerHTML = "<span>Collapse</span>";
expnd.onclick = function(e){
document.getElementById(path).checked = false;
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
var refrsh = document.createElement("li");
list.appendChild(refrsh);
refrsh.innerHTML = "<span>Refresh</span>";
refrsh.onclick = function(e){
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
} else {
expnd.innerHTML = "<span>Expand</span>";
expnd.onclick = function(e){
document.getElementById(path).checked = true;
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
var upload = document.createElement("li");
list.appendChild(upload);
upload.innerHTML = "<span>Upload</span>";
upload.onclick = function(e){
var pathEl = document.getElementById("upload-path");
if(pathEl){
var subPath = pathEl.value;
if(subPath.lastIndexOf("/") < 1) pathEl.value = path+subPath;
else pathEl.value = path.substring(subPath.lastIndexOf("/"))+subPath;
}
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
var delFile = document.createElement("li");
list.appendChild(delFile);
delFile.innerHTML = "<span>Delete</span>";
delFile.onclick = function(e){
httpDelete(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
function fillFileMenu(el, path){
var list = document.createElement("ul");
el.appendChild(list);
var action = document.createElement("li");
list.appendChild(action);
if(isTextFile(path)){
action.innerHTML = "<span>Edit</span>";
action.onclick = function(e){
editor.loadUrl(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
} else if(isImageFile(path)){
action.innerHTML = "<span>Preview</span>";
action.onclick = function(e){
loadPreview(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
var download = document.createElement("li");
list.appendChild(download);
download.innerHTML = "<span>Download</span>";
download.onclick = function(e){
loadDownload(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
var delFile = document.createElement("li");
list.appendChild(delFile);
delFile.innerHTML = "<span>Delete</span>";
delFile.onclick = function(e){
httpDelete(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
function showContextMenu(e, path, isfile){
var divContext = document.createElement("div");
var scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft;
var left = e.clientX + scrollLeft;
var top = e.clientY + scrollTop;
divContext.className = 'contextMenu';
divContext.style.display = 'block';
divContext.style.left = left + 'px';
divContext.style.top = top + 'px';
if(isfile) fillFileMenu(divContext, path);
else fillFolderMenu(divContext, path);
document.body.appendChild(divContext);
var width = divContext.offsetWidth;
var height = divContext.offsetHeight;
divContext.onmouseout = function(e){
if(e.clientX < left || e.clientX > (left + width) || e.clientY < top || e.clientY > (top + height)){
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(divContext);
}
};
}
function createTreeLeaf(path, name, size){
var leaf = document.createElement("li");
leaf.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
var label = document.createElement("span");
label.textContent = name.toLowerCase();
leaf.appendChild(label);
leaf.onclick = function(e){
if(isTextFile(leaf.id)){
editor.loadUrl(leaf.id);
} else if(isImageFile(leaf.id)){
loadPreview(leaf.id);
}
};
leaf.oncontextmenu = function(e){
e.preventDefault();
e.stopPropagation();
showContextMenu(e, leaf.id, true);
};
return leaf;
}
function createTreeBranch(path, name, disabled){
var leaf = document.createElement("li");
var check = document.createElement("input");
check.type = "checkbox";
check.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
if(typeof disabled !== "undefined" && disabled) check.disabled = "disabled";
leaf.appendChild(check);
var label = document.createElement("label");
label.for = check.id;
label.textContent = name.toLowerCase();
leaf.appendChild(label);
check.onchange = function(e){
if(check.checked){
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, check.id);
}
};
label.onclick = function(e){
if(!check.checked){
check.checked = true;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, check.id);
} else {
check.checked = false;
}
};
leaf.oncontextmenu = function(e){
e.preventDefault();
e.stopPropagation();
showContextMenu(e, check.id, false);
}
return leaf;
}
function addList(parent, path, items){
var list = document.createElement("ul");
parent.appendChild(list);
var ll = items.length;
for(var i = 0; i < ll; i++){
var item = items[i];
var itemEl;
if(item.type === "file"){
itemEl = createTreeLeaf(path, item.name, item.size);
} else {
itemEl = createTreeBranch(path, item.name);
}
list.appendChild(itemEl);
}
}
function isTextFile(path){
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
if(typeof ext !== undefined){
switch(ext){
case "txt":
case "htm":
case "html":
case "js":
case "json":
case "c":
case "h":
case "cpp":
case "css":
case "xml":
return true;
}
}
return false;
}
function isImageFile(path){
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
if(typeof ext !== undefined){
switch(ext){
case "png":
case "jpg":
case "gif":
case "ico":
return true;
}
}
return false;
}
this.refreshPath = function(path){
if(path.lastIndexOf('/') < 1){
path = '/';
treeRoot.removeChild(treeRoot.childNodes[0]);
httpGet(treeRoot, "/");
} else {
path = path.substring(0, path.lastIndexOf('/'));
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
}
};
function delCb(path){
return function(){
if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200){
alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
} else {
if(path.lastIndexOf('/') < 1){
path = '/';
treeRoot.removeChild(treeRoot.childNodes[0]);
httpGet(treeRoot, "/");
} else {
path = path.substring(0, path.lastIndexOf('/'));
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
}
}
}
}
}
function httpDelete(filename){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = delCb(filename);
var formData = new FormData();
formData.append("path", filename);
xmlHttp.open("DELETE", "/edit");
xmlHttp.send(formData);
}
function getCb(parent, path){
return function(){
if (xmlHttp.readyState == 4){
//clear loading
if(xmlHttp.status == 200) addList(parent, path, JSON.parse(xmlHttp.responseText));
}
}
}
function httpGet(parent, path){
xmlHttp = new XMLHttpRequest(parent, path);
xmlHttp.onreadystatechange = getCb(parent, path);
xmlHttp.open("GET", "/list?dir="+path, true);
xmlHttp.send(null);
//start loading
}
httpGet(treeRoot, "/");
return this;
}
function createEditor(element, file, lang, theme, type){
function getLangFromFilename(filename){
var lang = "plain";
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
if(typeof ext !== undefined){
switch(ext){
case "txt": lang = "plain"; break;
case "htm": lang = "html"; break;
case "js": lang = "javascript"; break;
case "c": lang = "c_cpp"; break;
case "cpp": lang = "c_cpp"; break;
case "css":
case "scss":
case "php":
case "html":
case "json":
case "xml":
lang = ext;
}
}
return lang;
}
if(typeof file === "undefined") file = "/index.htm";
if(typeof lang === "undefined"){
lang = getLangFromFilename(file);
}
if(typeof theme === "undefined") theme = "textmate";
if(typeof type === "undefined"){
type = "text/"+lang;
if(lang === "c_cpp") type = "text/plain";
}
var xmlHttp = null;
var editor = ace.edit(element);
//post
function httpPostProcessRequest(){
if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
}
}
function httpPost(filename, data, type){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpPostProcessRequest;
var formData = new FormData();
formData.append("data", new Blob([data], { type: type }), filename);
xmlHttp.open("POST", "/edit");
xmlHttp.send(formData);
}
//get
function httpGetProcessRequest(){
if (xmlHttp.readyState == 4){
document.getElementById("preview").style.display = "none";
document.getElementById("editor").style.display = "block";
if(xmlHttp.status == 200) editor.setValue(xmlHttp.responseText);
else editor.setValue("");
editor.clearSelection();
}
}
function httpGet(theUrl){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpGetProcessRequest;
xmlHttp.open("GET", theUrl, true);
xmlHttp.send(null);
}
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
editor.setTheme("ace/theme/"+theme);
editor.$blockScrolling = Infinity;
editor.getSession().setUseSoftTabs(true);
editor.getSession().setTabSize(2);
editor.setHighlightActiveLine(true);
editor.setShowPrintMargin(false);
editor.commands.addCommand({
name: 'saveCommand',
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
exec: function(editor) {
httpPost(file, editor.getValue()+"", type);
},
readOnly: false
});
editor.commands.addCommand({
name: 'undoCommand',
bindKey: {win: 'Ctrl-Z', mac: 'Command-Z'},
exec: function(editor) {
editor.getSession().getUndoManager().undo(false);
},
readOnly: false
});
editor.commands.addCommand({
name: 'redoCommand',
bindKey: {win: 'Ctrl-Shift-Z', mac: 'Command-Shift-Z'},
exec: function(editor) {
editor.getSession().getUndoManager().redo(false);
},
readOnly: false
});
httpGet(file);
editor.loadUrl = function(filename){
file = filename;
lang = getLangFromFilename(file);
type = "text/"+lang;
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
httpGet(file);
}
return editor;
}
function onBodyLoad(){
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { vars[key] = value; });
var editor = createEditor("editor", vars.file, vars.lang, vars.theme);
var tree = createTree("tree", editor);
createFileUploader("uploader", tree, editor);
};
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.9/ace.js" type="text/javascript" charset="utf-8"></script>
</head>
<body onload="onBodyLoad();">
<div id="uploader"></div>
<div id="tree"></div>
<div id="editor"></div>
<div id="preview" style="display:none;"></div>
<iframe id=download-frame style='display:none;'></iframe>
</body>
</html>

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>ESP Index</title>
<style>
body {
background-color:black;
color:white;
}
</style>
<script type="text/javascript">
function onBodyLoad(){
console.log("we are loaded!!");
}
</script>
</head>
<body id="index" onload="onBodyLoad()">
<h1>ESP8266 Pin Functions</h1>
<img src="pins.png" />
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

View File

@ -0,0 +1,132 @@
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
const char* ssid = "........";
const char* password = "........";
WebServer server(80);
//Check if header is present and correct
bool is_authentified() {
Serial.println("Enter is_authentified");
if (server.hasHeader("Cookie")) {
Serial.print("Found cookie: ");
String cookie = server.header("Cookie");
Serial.println(cookie);
if (cookie.indexOf("ESPSESSIONID=1") != -1) {
Serial.println("Authentification Successful");
return true;
}
}
Serial.println("Authentification Failed");
return false;
}
//login page, also called for disconnect
void handleLogin() {
String msg;
if (server.hasHeader("Cookie")) {
Serial.print("Found cookie: ");
String cookie = server.header("Cookie");
Serial.println(cookie);
}
if (server.hasArg("DISCONNECT")) {
Serial.println("Disconnection");
server.sendHeader("Location", "/login");
server.sendHeader("Cache-Control", "no-cache");
server.sendHeader("Set-Cookie", "ESPSESSIONID=0");
server.send(301);
return;
}
if (server.hasArg("USERNAME") && server.hasArg("PASSWORD")) {
if (server.arg("USERNAME") == "admin" && server.arg("PASSWORD") == "admin") {
server.sendHeader("Location", "/");
server.sendHeader("Cache-Control", "no-cache");
server.sendHeader("Set-Cookie", "ESPSESSIONID=1");
server.send(301);
Serial.println("Log in Successful");
return;
}
msg = "Wrong username/password! try again.";
Serial.println("Log in Failed");
}
String content = "<html><body><form action='/login' method='POST'>To log in, please use : admin/admin<br>";
content += "User:<input type='text' name='USERNAME' placeholder='user name'><br>";
content += "Password:<input type='password' name='PASSWORD' placeholder='password'><br>";
content += "<input type='submit' name='SUBMIT' value='Submit'></form>" + msg + "<br>";
content += "You also can go <a href='/inline'>here</a></body></html>";
server.send(200, "text/html", content);
}
//root page can be accessed only if authentification is ok
void handleRoot() {
Serial.println("Enter handleRoot");
String header;
if (!is_authentified()) {
server.sendHeader("Location", "/login");
server.sendHeader("Cache-Control", "no-cache");
server.send(301);
return;
}
String content = "<html><body><H2>hello, you successfully connected to esp8266!</H2><br>";
if (server.hasHeader("User-Agent")) {
content += "the user agent used is : " + server.header("User-Agent") + "<br><br>";
}
content += "You can access this page until you <a href=\"/login?DISCONNECT=YES\">disconnect</a></body></html>";
server.send(200, "text/html", content);
}
//no need authentification
void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}
void setup(void) {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
server.on("/", handleRoot);
server.on("/login", handleLogin);
server.on("/inline", []() {
server.send(200, "text/plain", "this works without need of authentification");
});
server.onNotFound(handleNotFound);
//here the list of headers to be recorded
const char * headerkeys[] = {"User-Agent", "Cookie"} ;
size_t headerkeyssize = sizeof(headerkeys) / sizeof(char*);
//ask server to track these headers
server.collectHeaders(headerkeys, headerkeyssize);
server.begin();
Serial.println("HTTP server started");
}
void loop(void) {
server.handleClient();
}

View File

@ -0,0 +1,67 @@
/*
To upload through terminal you can use: curl -F "image=@firmware.bin" esp8266-webupdate.local/update
*/
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
const char* host = "esp32-webupdate";
const char* ssid = "........";
const char* password = "........";
WebServer server(80);
const char* serverIndex = "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";
void setup(void) {
Serial.begin(115200);
Serial.println();
Serial.println("Booting Sketch...");
WiFi.mode(WIFI_AP_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() == WL_CONNECTED) {
MDNS.begin(host);
server.on("/", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", serverIndex);
});
server.on("/update", HTTP_POST, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
ESP.restart();
}, []() {
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
Serial.setDebugOutput(true);
Serial.printf("Update: %s\n", upload.filename.c_str());
if (!Update.begin()) { //start with max available size
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { //true to set the size to the current progress
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(Serial);
}
Serial.setDebugOutput(false);
}
});
server.begin();
MDNS.addService("http", "tcp", 80);
Serial.printf("Ready! Open http://%s.local in your browser\n", host);
} else {
Serial.println("WiFi Failed");
}
}
void loop(void) {
server.handleClient();
delay(1);
}

View File

@ -0,0 +1,38 @@
#######################################
# Syntax Coloring Map For Ultrasound
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
WebServer KEYWORD1
WebServerSecure KEYWORD1
HTTPMethod KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
handleClient KEYWORD2
on KEYWORD2
addHandler KEYWORD2
uri KEYWORD2
method KEYWORD2
client KEYWORD2
send KEYWORD2
arg KEYWORD2
argName KEYWORD2
args KEYWORD2
hasArg KEYWORD2
onNotFound KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
HTTP_GET LITERAL1
HTTP_POST LITERAL1
HTTP_ANY LITERAL1
CONTENT_LENGTH_UNKNOWN LITERAL1

View File

@ -0,0 +1,9 @@
name=WebServer
version=1.0
author=Ivan Grokhotkov
maintainer=Ivan Grokhtkov <ivan@esp8266.com>
sentence=Simple web server library
paragraph=The library supports HTTP GET and POST requests, provides argument parsing, handles one client at a time.
category=Communication
url=
architectures=esp32

View File

@ -0,0 +1,616 @@
/*
Parsing.cpp - HTTP request parsing.
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/
#include <Arduino.h>
#include "WiFiServer.h"
#include "WiFiClient.h"
#include "WebServer.h"
#include "detail/mimetable.h"
//#define DEBUG_ESP_HTTP_SERVER
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serial
#endif
static const char Content_Type[] PROGMEM = "Content-Type";
static const char filename[] PROGMEM = "filename";
static char* readBytesWithTimeout(WiFiClient& client, size_t maxLength, size_t& dataLength, int timeout_ms)
{
char *buf = nullptr;
dataLength = 0;
while (dataLength < maxLength) {
int tries = timeout_ms;
size_t newLength;
while (!(newLength = client.available()) && tries--) delay(1);
if (!newLength) {
break;
}
if (!buf) {
buf = (char *) malloc(newLength + 1);
if (!buf) {
return nullptr;
}
}
else {
char* newBuf = (char *) realloc(buf, dataLength + newLength + 1);
if (!newBuf) {
free(buf);
return nullptr;
}
buf = newBuf;
}
client.readBytes(buf + dataLength, newLength);
dataLength += newLength;
buf[dataLength] = '\0';
}
return buf;
}
bool WebServer::_parseRequest(WiFiClient& client) {
// Read the first line of HTTP request
String req = client.readStringUntil('\r');
client.readStringUntil('\n');
//reset header value
for (int i = 0; i < _headerKeysCount; ++i) {
_currentHeaders[i].value =String();
}
// First line of HTTP request looks like "GET /path HTTP/1.1"
// Retrieve the "/path" part by finding the spaces
int addr_start = req.indexOf(' ');
int addr_end = req.indexOf(' ', addr_start + 1);
if (addr_start == -1 || addr_end == -1) {
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Invalid request: ");
DEBUG_OUTPUT.println(req);
#endif
return false;
}
String methodStr = req.substring(0, addr_start);
String url = req.substring(addr_start + 1, addr_end);
String versionEnd = req.substring(addr_end + 8);
_currentVersion = atoi(versionEnd.c_str());
String searchStr = "";
int hasSearch = url.indexOf('?');
if (hasSearch != -1){
searchStr = url.substring(hasSearch + 1);
url = url.substring(0, hasSearch);
}
_currentUri = url;
_chunked = false;
HTTPMethod method = HTTP_GET;
if (methodStr == F("POST")) {
method = HTTP_POST;
} else if (methodStr == F("DELETE")) {
method = HTTP_DELETE;
} else if (methodStr == F("OPTIONS")) {
method = HTTP_OPTIONS;
} else if (methodStr == F("PUT")) {
method = HTTP_PUT;
} else if (methodStr == F("PATCH")) {
method = HTTP_PATCH;
}
_currentMethod = method;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("method: ");
DEBUG_OUTPUT.print(methodStr);
DEBUG_OUTPUT.print(" url: ");
DEBUG_OUTPUT.print(url);
DEBUG_OUTPUT.print(" search: ");
DEBUG_OUTPUT.println(searchStr);
#endif
//attach handler
RequestHandler* handler;
for (handler = _firstHandler; handler; handler = handler->next()) {
if (handler->canHandle(_currentMethod, _currentUri))
break;
}
_currentHandler = handler;
String formData;
// below is needed only when POST type request
if (method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){
String boundaryStr;
String headerName;
String headerValue;
bool isForm = false;
bool isEncoded = false;
uint32_t contentLength = 0;
//parse headers
while(1){
req = client.readStringUntil('\r');
client.readStringUntil('\n');
if (req == "") break;//no moar headers
int headerDiv = req.indexOf(':');
if (headerDiv == -1){
break;
}
headerName = req.substring(0, headerDiv);
headerValue = req.substring(headerDiv + 1);
headerValue.trim();
_collectHeader(headerName.c_str(),headerValue.c_str());
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("headerName: ");
DEBUG_OUTPUT.println(headerName);
DEBUG_OUTPUT.print("headerValue: ");
DEBUG_OUTPUT.println(headerValue);
#endif
if (headerName.equalsIgnoreCase(FPSTR(Content_Type))){
using namespace mime;
if (headerValue.startsWith(FPSTR(mimeTable[txt].mimeType))){
isForm = false;
} else if (headerValue.startsWith(F("application/x-www-form-urlencoded"))){
isForm = false;
isEncoded = true;
} else if (headerValue.startsWith(F("multipart/"))){
boundaryStr = headerValue.substring(headerValue.indexOf('=') + 1);
boundaryStr.replace("\"","");
isForm = true;
}
} else if (headerName.equalsIgnoreCase(F("Content-Length"))){
contentLength = headerValue.toInt();
} else if (headerName.equalsIgnoreCase(F("Host"))){
_hostHeader = headerValue;
}
}
if (!isForm){
size_t plainLength;
char* plainBuf = readBytesWithTimeout(client, contentLength, plainLength, HTTP_MAX_POST_WAIT);
if (plainLength < contentLength) {
free(plainBuf);
return false;
}
if (contentLength > 0) {
if(isEncoded){
//url encoded form
if (searchStr != "") searchStr += '&';
searchStr += plainBuf;
}
_parseArguments(searchStr);
if(!isEncoded){
//plain post json or other data
RequestArgument& arg = _currentArgs[_currentArgCount++];
arg.key = F("plain");
arg.value = String(plainBuf);
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Plain: ");
DEBUG_OUTPUT.println(plainBuf);
#endif
free(plainBuf);
} else {
// No content - but we can still have arguments in the URL.
_parseArguments(searchStr);
}
}
if (isForm){
_parseArguments(searchStr);
if (!_parseForm(client, boundaryStr, contentLength)) {
return false;
}
}
} else {
String headerName;
String headerValue;
//parse headers
while(1){
req = client.readStringUntil('\r');
client.readStringUntil('\n');
if (req == "") break;//no moar headers
int headerDiv = req.indexOf(':');
if (headerDiv == -1){
break;
}
headerName = req.substring(0, headerDiv);
headerValue = req.substring(headerDiv + 2);
_collectHeader(headerName.c_str(),headerValue.c_str());
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("headerName: ");
DEBUG_OUTPUT.println(headerName);
DEBUG_OUTPUT.print("headerValue: ");
DEBUG_OUTPUT.println(headerValue);
#endif
if (headerName.equalsIgnoreCase("Host")){
_hostHeader = headerValue;
}
}
_parseArguments(searchStr);
}
client.flush();
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Request: ");
DEBUG_OUTPUT.println(url);
DEBUG_OUTPUT.print(" Arguments: ");
DEBUG_OUTPUT.println(searchStr);
#endif
return true;
}
bool WebServer::_collectHeader(const char* headerName, const char* headerValue) {
for (int i = 0; i < _headerKeysCount; i++) {
if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) {
_currentHeaders[i].value=headerValue;
return true;
}
}
return false;
}
void WebServer::_parseArguments(String data) {
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("args: ");
DEBUG_OUTPUT.println(data);
#endif
if (_currentArgs)
delete[] _currentArgs;
_currentArgs = 0;
if (data.length() == 0) {
_currentArgCount = 0;
_currentArgs = new RequestArgument[1];
return;
}
_currentArgCount = 1;
for (int i = 0; i < (int)data.length(); ) {
i = data.indexOf('&', i);
if (i == -1)
break;
++i;
++_currentArgCount;
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("args count: ");
DEBUG_OUTPUT.println(_currentArgCount);
#endif
_currentArgs = new RequestArgument[_currentArgCount+1];
int pos = 0;
int iarg;
for (iarg = 0; iarg < _currentArgCount;) {
int equal_sign_index = data.indexOf('=', pos);
int next_arg_index = data.indexOf('&', pos);
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("pos ");
DEBUG_OUTPUT.print(pos);
DEBUG_OUTPUT.print("=@ ");
DEBUG_OUTPUT.print(equal_sign_index);
DEBUG_OUTPUT.print(" &@ ");
DEBUG_OUTPUT.println(next_arg_index);
#endif
if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) {
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("arg missing value: ");
DEBUG_OUTPUT.println(iarg);
#endif
if (next_arg_index == -1)
break;
pos = next_arg_index + 1;
continue;
}
RequestArgument& arg = _currentArgs[iarg];
arg.key = urlDecode(data.substring(pos, equal_sign_index));
arg.value = urlDecode(data.substring(equal_sign_index + 1, next_arg_index));
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("arg ");
DEBUG_OUTPUT.print(iarg);
DEBUG_OUTPUT.print(" key: ");
DEBUG_OUTPUT.print(arg.key);
DEBUG_OUTPUT.print(" value: ");
DEBUG_OUTPUT.println(arg.value);
#endif
++iarg;
if (next_arg_index == -1)
break;
pos = next_arg_index + 1;
}
_currentArgCount = iarg;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("args count: ");
DEBUG_OUTPUT.println(_currentArgCount);
#endif
}
void WebServer::_uploadWriteByte(uint8_t b){
if (_currentUpload->currentSize == HTTP_UPLOAD_BUFLEN){
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->totalSize += _currentUpload->currentSize;
_currentUpload->currentSize = 0;
}
_currentUpload->buf[_currentUpload->currentSize++] = b;
}
uint8_t WebServer::_uploadReadByte(WiFiClient& client){
int res = client.read();
if(res == -1){
while(!client.available() && client.connected())
yield();
res = client.read();
}
return (uint8_t)res;
}
bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
(void) len;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Parse Form: Boundary: ");
DEBUG_OUTPUT.print(boundary);
DEBUG_OUTPUT.print(" Length: ");
DEBUG_OUTPUT.println(len);
#endif
String line;
int retry = 0;
do {
line = client.readStringUntil('\r');
++retry;
} while (line.length() == 0 && retry < 3);
client.readStringUntil('\n');
//start reading the form
if (line == ("--"+boundary)){
RequestArgument* postArgs = new RequestArgument[32];
int postArgsLen = 0;
while(1){
String argName;
String argValue;
String argType;
String argFilename;
bool argIsFile = false;
line = client.readStringUntil('\r');
client.readStringUntil('\n');
if (line.length() > 19 && line.substring(0, 19).equalsIgnoreCase(F("Content-Disposition"))){
int nameStart = line.indexOf('=');
if (nameStart != -1){
argName = line.substring(nameStart+2);
nameStart = argName.indexOf('=');
if (nameStart == -1){
argName = argName.substring(0, argName.length() - 1);
} else {
argFilename = argName.substring(nameStart+2, argName.length() - 1);
argName = argName.substring(0, argName.indexOf('"'));
argIsFile = true;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("PostArg FileName: ");
DEBUG_OUTPUT.println(argFilename);
#endif
//use GET to set the filename if uploading using blob
if (argFilename == F("blob") && hasArg(FPSTR(filename)))
argFilename = arg(FPSTR(filename));
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("PostArg Name: ");
DEBUG_OUTPUT.println(argName);
#endif
using namespace mime;
argType = FPSTR(mimeTable[txt].mimeType);
line = client.readStringUntil('\r');
client.readStringUntil('\n');
if (line.length() > 12 && line.substring(0, 12).equalsIgnoreCase(FPSTR(Content_Type))){
argType = line.substring(line.indexOf(':')+2);
//skip next line
client.readStringUntil('\r');
client.readStringUntil('\n');
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("PostArg Type: ");
DEBUG_OUTPUT.println(argType);
#endif
if (!argIsFile){
while(1){
line = client.readStringUntil('\r');
client.readStringUntil('\n');
if (line.startsWith("--"+boundary)) break;
if (argValue.length() > 0) argValue += "\n";
argValue += line;
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("PostArg Value: ");
DEBUG_OUTPUT.println(argValue);
DEBUG_OUTPUT.println();
#endif
RequestArgument& arg = postArgs[postArgsLen++];
arg.key = argName;
arg.value = argValue;
if (line == ("--"+boundary+"--")){
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("Done Parsing POST");
#endif
break;
}
} else {
_currentUpload.reset(new HTTPUpload());
_currentUpload->status = UPLOAD_FILE_START;
_currentUpload->name = argName;
_currentUpload->filename = argFilename;
_currentUpload->type = argType;
_currentUpload->totalSize = 0;
_currentUpload->currentSize = 0;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Start File: ");
DEBUG_OUTPUT.print(_currentUpload->filename);
DEBUG_OUTPUT.print(" Type: ");
DEBUG_OUTPUT.println(_currentUpload->type);
#endif
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->status = UPLOAD_FILE_WRITE;
uint8_t argByte = _uploadReadByte(client);
readfile:
while(argByte != 0x0D){
if (!client.connected()) return _parseFormUploadAborted();
_uploadWriteByte(argByte);
argByte = _uploadReadByte(client);
}
argByte = _uploadReadByte(client);
if (!client.connected()) return _parseFormUploadAborted();
if (argByte == 0x0A){
argByte = _uploadReadByte(client);
if (!client.connected()) return _parseFormUploadAborted();
if ((char)argByte != '-'){
//continue reading the file
_uploadWriteByte(0x0D);
_uploadWriteByte(0x0A);
goto readfile;
} else {
argByte = _uploadReadByte(client);
if (!client.connected()) return _parseFormUploadAborted();
if ((char)argByte != '-'){
//continue reading the file
_uploadWriteByte(0x0D);
_uploadWriteByte(0x0A);
_uploadWriteByte((uint8_t)('-'));
goto readfile;
}
}
uint8_t endBuf[boundary.length()];
client.readBytes(endBuf, boundary.length());
if (strstr((const char*)endBuf, boundary.c_str()) != NULL){
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->totalSize += _currentUpload->currentSize;
_currentUpload->status = UPLOAD_FILE_END;
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("End File: ");
DEBUG_OUTPUT.print(_currentUpload->filename);
DEBUG_OUTPUT.print(" Type: ");
DEBUG_OUTPUT.print(_currentUpload->type);
DEBUG_OUTPUT.print(" Size: ");
DEBUG_OUTPUT.println(_currentUpload->totalSize);
#endif
line = client.readStringUntil(0x0D);
client.readStringUntil(0x0A);
if (line == "--"){
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("Done Parsing POST");
#endif
break;
}
continue;
} else {
_uploadWriteByte(0x0D);
_uploadWriteByte(0x0A);
_uploadWriteByte((uint8_t)('-'));
_uploadWriteByte((uint8_t)('-'));
uint32_t i = 0;
while(i < boundary.length()){
_uploadWriteByte(endBuf[i++]);
}
argByte = _uploadReadByte(client);
goto readfile;
}
} else {
_uploadWriteByte(0x0D);
goto readfile;
}
break;
}
}
}
}
int iarg;
int totalArgs = ((32 - postArgsLen) < _currentArgCount)?(32 - postArgsLen):_currentArgCount;
for (iarg = 0; iarg < totalArgs; iarg++){
RequestArgument& arg = postArgs[postArgsLen++];
arg.key = _currentArgs[iarg].key;
arg.value = _currentArgs[iarg].value;
}
if (_currentArgs) delete[] _currentArgs;
_currentArgs = new RequestArgument[postArgsLen];
for (iarg = 0; iarg < postArgsLen; iarg++){
RequestArgument& arg = _currentArgs[iarg];
arg.key = postArgs[iarg].key;
arg.value = postArgs[iarg].value;
}
_currentArgCount = iarg;
if (postArgs)
delete[] postArgs;
return true;
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Error: line: ");
DEBUG_OUTPUT.println(line);
#endif
return false;
}
String WebServer::urlDecode(const String& text)
{
String decoded = "";
char temp[] = "0x00";
unsigned int len = text.length();
unsigned int i = 0;
while (i < len)
{
char decodedChar;
char encodedChar = text.charAt(i++);
if ((encodedChar == '%') && (i + 1 < len))
{
temp[2] = text.charAt(i++);
temp[3] = text.charAt(i++);
decodedChar = strtol(temp, NULL, 16);
}
else {
if (encodedChar == '+')
{
decodedChar = ' ';
}
else {
decodedChar = encodedChar; // normal ascii char
}
}
decoded += decodedChar;
}
return decoded;
}
bool WebServer::_parseFormUploadAborted(){
_currentUpload->status = UPLOAD_FILE_ABORTED;
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
return false;
}

View File

@ -0,0 +1,676 @@
/*
WebServer.cpp - Dead simple web-server.
Supports only one simultaneous client, knows how to handle GET and POST.
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/
#include <Arduino.h>
#include <libb64/cencode.h>
#include "WiFiServer.h"
#include "WiFiClient.h"
#include "WebServer.h"
#include "FS.h"
#include "detail/RequestHandlersImpl.h"
#include "mbedtls/md5.h"
//#define DEBUG_ESP_HTTP_SERVER
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serial
#endif
static const char AUTHORIZATION_HEADER[] = "Authorization";
static const char qop_auth[] = "qop=auth";
static const char WWW_Authenticate[] = "WWW-Authenticate";
static const char Content_Length[] = "Content-Length";
WebServer::WebServer(IPAddress addr, int port)
: _server(addr, port)
, _currentMethod(HTTP_ANY)
, _currentVersion(0)
, _currentStatus(HC_NONE)
, _statusChange(0)
, _currentHandler(nullptr)
, _firstHandler(nullptr)
, _lastHandler(nullptr)
, _currentArgCount(0)
, _currentArgs(nullptr)
, _headerKeysCount(0)
, _currentHeaders(nullptr)
, _contentLength(0)
, _chunked(false)
{
}
WebServer::WebServer(int port)
: _server(port)
, _currentMethod(HTTP_ANY)
, _currentVersion(0)
, _currentStatus(HC_NONE)
, _statusChange(0)
, _currentHandler(nullptr)
, _firstHandler(nullptr)
, _lastHandler(nullptr)
, _currentArgCount(0)
, _currentArgs(nullptr)
, _headerKeysCount(0)
, _currentHeaders(nullptr)
, _contentLength(0)
, _chunked(false)
{
}
WebServer::~WebServer() {
_server.close();
if (_currentHeaders)
delete[]_currentHeaders;
RequestHandler* handler = _firstHandler;
while (handler) {
RequestHandler* next = handler->next();
delete handler;
handler = next;
}
}
void WebServer::begin() {
close();
_server.begin();
}
void WebServer::begin(uint16_t port) {
close();
_server.begin(port);
}
String WebServer::_extractParam(String& authReq,const String& param,const char delimit){
int _begin = authReq.indexOf(param);
if (_begin == -1)
return "";
return authReq.substring(_begin+param.length(),authReq.indexOf(delimit,_begin+param.length()));
}
static String md5str(String &in){
char out[33] = {0};
mbedtls_md5_context _ctx;
uint8_t i;
uint8_t * _buf = (uint8_t*)malloc(16);
if(_buf == NULL)
return String(out);
memset(_buf, 0x00, 16);
mbedtls_md5_init(&_ctx);
mbedtls_md5_starts(&_ctx);
mbedtls_md5_update(&_ctx, (const uint8_t *)in.c_str(), in.length());
mbedtls_md5_finish(&_ctx, _buf);
for(i = 0; i < 16; i++) {
sprintf(out + (i * 2), "%02x", _buf[i]);
}
out[32] = 0;
free(_buf);
return String(out);
}
bool WebServer::authenticate(const char * username, const char * password){
if(hasHeader(FPSTR(AUTHORIZATION_HEADER))) {
String authReq = header(FPSTR(AUTHORIZATION_HEADER));
if(authReq.startsWith(F("Basic"))){
authReq = authReq.substring(6);
authReq.trim();
char toencodeLen = strlen(username)+strlen(password)+1;
char *toencode = new char[toencodeLen + 1];
if(toencode == NULL){
authReq = "";
return false;
}
char *encoded = new char[base64_encode_expected_len(toencodeLen)+1];
if(encoded == NULL){
authReq = "";
delete[] toencode;
return false;
}
sprintf(toencode, "%s:%s", username, password);
if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equalsConstantTime(encoded)) {
authReq = "";
delete[] toencode;
delete[] encoded;
return true;
}
delete[] toencode;
delete[] encoded;
} else if(authReq.startsWith(F("Digest"))) {
authReq = authReq.substring(7);
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println(authReq);
#endif
String _username = _extractParam(authReq,F("username=\""));
if(!_username.length() || _username != String(username)) {
authReq = "";
return false;
}
// extracting required parameters for RFC 2069 simpler Digest
String _realm = _extractParam(authReq, F("realm=\""));
String _nonce = _extractParam(authReq, F("nonce=\""));
String _uri = _extractParam(authReq, F("uri=\""));
String _response = _extractParam(authReq, F("response=\""));
String _opaque = _extractParam(authReq, F("opaque=\""));
if((!_realm.length()) || (!_nonce.length()) || (!_uri.length()) || (!_response.length()) || (!_opaque.length())) {
authReq = "";
return false;
}
if((_opaque != _sopaque) || (_nonce != _snonce) || (_realm != _srealm)) {
authReq = "";
return false;
}
// parameters for the RFC 2617 newer Digest
String _nc,_cnonce;
if(authReq.indexOf(FPSTR(qop_auth)) != -1) {
_nc = _extractParam(authReq, F("nc="), ',');
_cnonce = _extractParam(authReq, F("cnonce=\""));
}
String _H1 = md5str(String(username) + ':' + _realm + ':' + String(password));
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("Hash of user:realm:pass=" + _H1);
#endif
String _H2 = "";
if(_currentMethod == HTTP_GET){
_H2 = md5str(String(F("GET:")) + _uri);
}else if(_currentMethod == HTTP_POST){
_H2 = md5str(String(F("POST:")) + _uri);
}else if(_currentMethod == HTTP_PUT){
_H2 = md5str(String(F("PUT:")) + _uri);
}else if(_currentMethod == HTTP_DELETE){
_H2 = md5str(String(F("DELETE:")) + _uri);
}else{
_H2 = md5str(String(F("GET:")) + _uri);
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("Hash of GET:uri=" + _H2);
#endif
String _responsecheck = "";
if(authReq.indexOf(FPSTR(qop_auth)) != -1) {
_responsecheck = md5str(_H1 + ':' + _nonce + ':' + _nc + ':' + _cnonce + F(":auth:") + _H2);
} else {
_responsecheck = md5str(_H1 + ':' + _nonce + ':' + _H2);
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("The Proper response=" +_responsecheck);
#endif
if(_response == _responsecheck){
authReq = "";
return true;
}
}
authReq = "";
}
return false;
}
String WebServer::_getRandomHexString() {
char buffer[33]; // buffer to hold 32 Hex Digit + /0
int i;
for(i = 0; i < 4; i++) {
sprintf (buffer + (i*8), "%08x", esp_random());
}
return String(buffer);
}
void WebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg) {
if(realm == NULL) {
_srealm = String(F("Login Required"));
} else {
_srealm = String(realm);
}
if(mode == BASIC_AUTH) {
sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Basic realm=\"")) + _srealm + String(F("\"")));
} else {
_snonce=_getRandomHexString();
_sopaque=_getRandomHexString();
sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Digest realm=\"")) +_srealm + String(F("\", qop=\"auth\", nonce=\"")) + _snonce + String(F("\", opaque=\"")) + _sopaque + String(F("\"")));
}
using namespace mime;
send(401, String(FPSTR(mimeTable[html].mimeType)), authFailMsg);
}
void WebServer::on(const String &uri, WebServer::THandlerFunction handler) {
on(uri, HTTP_ANY, handler);
}
void WebServer::on(const String &uri, HTTPMethod method, WebServer::THandlerFunction fn) {
on(uri, method, fn, _fileUploadHandler);
}
void WebServer::on(const String &uri, HTTPMethod method, WebServer::THandlerFunction fn, WebServer::THandlerFunction ufn) {
_addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method));
}
void WebServer::addHandler(RequestHandler* handler) {
_addRequestHandler(handler);
}
void WebServer::_addRequestHandler(RequestHandler* handler) {
if (!_lastHandler) {
_firstHandler = handler;
_lastHandler = handler;
}
else {
_lastHandler->next(handler);
_lastHandler = handler;
}
}
void WebServer::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header) {
_addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header));
}
void WebServer::handleClient() {
if (_currentStatus == HC_NONE) {
WiFiClient client = _server.available();
if (!client) {
return;
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("New client");
#endif
_currentClient = client;
_currentStatus = HC_WAIT_READ;
_statusChange = millis();
}
bool keepCurrentClient = false;
bool callYield = false;
if (_currentClient.connected()) {
switch (_currentStatus) {
case HC_NONE:
// No-op to avoid C++ compiler warning
break;
case HC_WAIT_READ:
// Wait for data from client to become available
if (_currentClient.available()) {
if (_parseRequest(_currentClient)) {
_currentClient.setTimeout(HTTP_MAX_SEND_WAIT);
_contentLength = CONTENT_LENGTH_NOT_SET;
_handleRequest();
if (_currentClient.connected()) {
_currentStatus = HC_WAIT_CLOSE;
_statusChange = millis();
keepCurrentClient = true;
}
}
} else { // !_currentClient.available()
if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) {
keepCurrentClient = true;
}
callYield = true;
}
break;
case HC_WAIT_CLOSE:
// Wait for client to close the connection
if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT) {
keepCurrentClient = true;
callYield = true;
}
}
}
if (!keepCurrentClient) {
_currentClient = WiFiClient();
_currentStatus = HC_NONE;
_currentUpload.reset();
}
if (callYield) {
yield();
}
}
void WebServer::close() {
_server.close();
_currentStatus = HC_NONE;
if(!_headerKeysCount)
collectHeaders(0, 0);
}
void WebServer::stop() {
close();
}
void WebServer::sendHeader(const String& name, const String& value, bool first) {
String headerLine = name;
headerLine += F(": ");
headerLine += value;
headerLine += "\r\n";
if (first) {
_responseHeaders = headerLine + _responseHeaders;
}
else {
_responseHeaders += headerLine;
}
}
void WebServer::setContentLength(const size_t contentLength) {
_contentLength = contentLength;
}
void WebServer::_prepareHeader(String& response, int code, const char* content_type, size_t contentLength) {
response = String(F("HTTP/1.")) + String(_currentVersion) + ' ';
response += String(code);
response += ' ';
response += _responseCodeToString(code);
response += "\r\n";
using namespace mime;
if (!content_type)
content_type = mimeTable[html].mimeType;
sendHeader(String(F("Content-Type")), String(FPSTR(content_type)), true);
if (_contentLength == CONTENT_LENGTH_NOT_SET) {
sendHeader(String(FPSTR(Content_Length)), String(contentLength));
} else if (_contentLength != CONTENT_LENGTH_UNKNOWN) {
sendHeader(String(FPSTR(Content_Length)), String(_contentLength));
} else if(_contentLength == CONTENT_LENGTH_UNKNOWN && _currentVersion){ //HTTP/1.1 or above client
//let's do chunked
_chunked = true;
sendHeader(String(F("Accept-Ranges")),String(F("none")));
sendHeader(String(F("Transfer-Encoding")),String(F("chunked")));
}
sendHeader(String(F("Connection")), String(F("close")));
response += _responseHeaders;
response += "\r\n";
_responseHeaders = "";
}
void WebServer::send(int code, const char* content_type, const String& content) {
String header;
// Can we asume the following?
//if(code == 200 && content.length() == 0 && _contentLength == CONTENT_LENGTH_NOT_SET)
// _contentLength = CONTENT_LENGTH_UNKNOWN;
_prepareHeader(header, code, content_type, content.length());
_currentClientWrite(header.c_str(), header.length());
if(content.length())
sendContent(content);
}
void WebServer::send_P(int code, PGM_P content_type, PGM_P content) {
size_t contentLength = 0;
if (content != NULL) {
contentLength = strlen_P(content);
}
String header;
char type[64];
memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type));
_prepareHeader(header, code, (const char* )type, contentLength);
_currentClientWrite(header.c_str(), header.length());
sendContent_P(content);
}
void WebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) {
String header;
char type[64];
memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type));
_prepareHeader(header, code, (const char* )type, contentLength);
sendContent(header);
sendContent_P(content, contentLength);
}
void WebServer::send(int code, char* content_type, const String& content) {
send(code, (const char*)content_type, content);
}
void WebServer::send(int code, const String& content_type, const String& content) {
send(code, (const char*)content_type.c_str(), content);
}
void WebServer::sendContent(const String& content) {
const char * footer = "\r\n";
size_t len = content.length();
if(_chunked) {
char * chunkSize = (char *)malloc(11);
if(chunkSize){
sprintf(chunkSize, "%x%s", len, footer);
_currentClientWrite(chunkSize, strlen(chunkSize));
free(chunkSize);
}
}
_currentClientWrite(content.c_str(), len);
if(_chunked){
_currentClient.write(footer, 2);
if (len == 0) {
_chunked = false;
}
}
}
void WebServer::sendContent_P(PGM_P content) {
sendContent_P(content, strlen_P(content));
}
void WebServer::sendContent_P(PGM_P content, size_t size) {
const char * footer = "\r\n";
if(_chunked) {
char * chunkSize = (char *)malloc(11);
if(chunkSize){
sprintf(chunkSize, "%x%s", size, footer);
_currentClientWrite(chunkSize, strlen(chunkSize));
free(chunkSize);
}
}
_currentClientWrite_P(content, size);
if(_chunked){
_currentClient.write(footer, 2);
if (size == 0) {
_chunked = false;
}
}
}
void WebServer::_streamFileCore(const size_t fileSize, const String & fileName, const String & contentType)
{
using namespace mime;
setContentLength(fileSize);
if (fileName.endsWith(String(FPSTR(mimeTable[gz].endsWith))) &&
contentType != String(FPSTR(mimeTable[gz].mimeType)) &&
contentType != String(FPSTR(mimeTable[none].mimeType))) {
sendHeader(F("Content-Encoding"), F("gzip"));
}
send(200, contentType, "");
}
String WebServer::arg(String name) {
for (int i = 0; i < _currentArgCount; ++i) {
if ( _currentArgs[i].key == name )
return _currentArgs[i].value;
}
return "";
}
String WebServer::arg(int i) {
if (i < _currentArgCount)
return _currentArgs[i].value;
return "";
}
String WebServer::argName(int i) {
if (i < _currentArgCount)
return _currentArgs[i].key;
return "";
}
int WebServer::args() {
return _currentArgCount;
}
bool WebServer::hasArg(String name) {
for (int i = 0; i < _currentArgCount; ++i) {
if (_currentArgs[i].key == name)
return true;
}
return false;
}
String WebServer::header(String name) {
for (int i = 0; i < _headerKeysCount; ++i) {
if (_currentHeaders[i].key.equalsIgnoreCase(name))
return _currentHeaders[i].value;
}
return "";
}
void WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
_headerKeysCount = headerKeysCount + 1;
if (_currentHeaders)
delete[]_currentHeaders;
_currentHeaders = new RequestArgument[_headerKeysCount];
_currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER);
for (int i = 1; i < _headerKeysCount; i++){
_currentHeaders[i].key = headerKeys[i-1];
}
}
String WebServer::header(int i) {
if (i < _headerKeysCount)
return _currentHeaders[i].value;
return "";
}
String WebServer::headerName(int i) {
if (i < _headerKeysCount)
return _currentHeaders[i].key;
return "";
}
int WebServer::headers() {
return _headerKeysCount;
}
bool WebServer::hasHeader(String name) {
for (int i = 0; i < _headerKeysCount; ++i) {
if ((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0))
return true;
}
return false;
}
String WebServer::hostHeader() {
return _hostHeader;
}
void WebServer::onFileUpload(THandlerFunction fn) {
_fileUploadHandler = fn;
}
void WebServer::onNotFound(THandlerFunction fn) {
_notFoundHandler = fn;
}
void WebServer::_handleRequest() {
bool handled = false;
if (!_currentHandler){
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("request handler not found");
#endif
}
else {
handled = _currentHandler->handle(*this, _currentMethod, _currentUri);
#ifdef DEBUG_ESP_HTTP_SERVER
if (!handled) {
DEBUG_OUTPUT.println("request handler failed to handle request");
}
#endif
}
if (!handled && _notFoundHandler) {
_notFoundHandler();
handled = true;
}
if (!handled) {
using namespace mime;
send(404, String(FPSTR(mimeTable[html].mimeType)), String(F("Not found: ")) + _currentUri);
handled = true;
}
if (handled) {
_finalizeResponse();
}
_currentUri = "";
}
void WebServer::_finalizeResponse() {
if (_chunked) {
sendContent("");
}
}
String WebServer::_responseCodeToString(int code) {
switch (code) {
case 100: return F("Continue");
case 101: return F("Switching Protocols");
case 200: return F("OK");
case 201: return F("Created");
case 202: return F("Accepted");
case 203: return F("Non-Authoritative Information");
case 204: return F("No Content");
case 205: return F("Reset Content");
case 206: return F("Partial Content");
case 300: return F("Multiple Choices");
case 301: return F("Moved Permanently");
case 302: return F("Found");
case 303: return F("See Other");
case 304: return F("Not Modified");
case 305: return F("Use Proxy");
case 307: return F("Temporary Redirect");
case 400: return F("Bad Request");
case 401: return F("Unauthorized");
case 402: return F("Payment Required");
case 403: return F("Forbidden");
case 404: return F("Not Found");
case 405: return F("Method Not Allowed");
case 406: return F("Not Acceptable");
case 407: return F("Proxy Authentication Required");
case 408: return F("Request Time-out");
case 409: return F("Conflict");
case 410: return F("Gone");
case 411: return F("Length Required");
case 412: return F("Precondition Failed");
case 413: return F("Request Entity Too Large");
case 414: return F("Request-URI Too Large");
case 415: return F("Unsupported Media Type");
case 416: return F("Requested range not satisfiable");
case 417: return F("Expectation Failed");
case 500: return F("Internal Server Error");
case 501: return F("Not Implemented");
case 502: return F("Bad Gateway");
case 503: return F("Service Unavailable");
case 504: return F("Gateway Time-out");
case 505: return F("HTTP Version not supported");
default: return F("");
}
}

View File

@ -0,0 +1,199 @@
/*
WebServer.h - Dead simple web-server.
Supports only one simultaneous client, knows how to handle GET and POST.
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/
#ifndef WEBSERVER_H
#define WEBSERVER_H
#include <functional>
#include <memory>
#include <WiFi.h>
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS };
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
UPLOAD_FILE_ABORTED };
enum HTTPClientStatus { HC_NONE, HC_WAIT_READ, HC_WAIT_CLOSE };
enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
#define HTTP_DOWNLOAD_UNIT_SIZE 1460
#ifndef HTTP_UPLOAD_BUFLEN
#define HTTP_UPLOAD_BUFLEN 2048
#endif
#define HTTP_MAX_DATA_WAIT 5000 //ms to wait for the client to send the request
#define HTTP_MAX_POST_WAIT 5000 //ms to wait for POST data to arrive
#define HTTP_MAX_SEND_WAIT 5000 //ms to wait for data chunk to be ACKed
#define HTTP_MAX_CLOSE_WAIT 2000 //ms to wait for the client to close the connection
#define CONTENT_LENGTH_UNKNOWN ((size_t) -1)
#define CONTENT_LENGTH_NOT_SET ((size_t) -2)
class WebServer;
typedef struct {
HTTPUploadStatus status;
String filename;
String name;
String type;
size_t totalSize; // file size
size_t currentSize; // size of data currently in buf
uint8_t buf[HTTP_UPLOAD_BUFLEN];
} HTTPUpload;
#include "detail/RequestHandler.h"
namespace fs {
class FS;
}
class WebServer
{
public:
WebServer(IPAddress addr, int port = 80);
WebServer(int port = 80);
virtual ~WebServer();
virtual void begin();
virtual void begin(uint16_t port);
virtual void handleClient();
virtual void close();
void stop();
bool authenticate(const char * username, const char * password);
void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = NULL, const String& authFailMsg = String("") );
typedef std::function<void(void)> THandlerFunction;
void on(const String &uri, THandlerFunction handler);
void on(const String &uri, HTTPMethod method, THandlerFunction fn);
void on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn);
void addHandler(RequestHandler* handler);
void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL );
void onNotFound(THandlerFunction fn); //called when handler is not assigned
void onFileUpload(THandlerFunction fn); //handle file uploads
String uri() { return _currentUri; }
HTTPMethod method() { return _currentMethod; }
virtual WiFiClient client() { return _currentClient; }
HTTPUpload& upload() { return *_currentUpload; }
String arg(String name); // get request argument value by name
String arg(int i); // get request argument value by number
String argName(int i); // get request argument name by number
int args(); // get arguments count
bool hasArg(String name); // check if argument exists
void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); // set the request headers to collect
String header(String name); // get request header value by name
String header(int i); // get request header value by number
String headerName(int i); // get request header name by number
int headers(); // get header count
bool hasHeader(String name); // check if header exists
String hostHeader(); // get request host header if available or empty String if not
// send response to the client
// code - HTTP response code, can be 200 or 404
// content_type - HTTP content type, like "text/plain" or "image/png"
// content - actual content body
void send(int code, const char* content_type = NULL, const String& content = String(""));
void send(int code, char* content_type, const String& content);
void send(int code, const String& content_type, const String& content);
void send_P(int code, PGM_P content_type, PGM_P content);
void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength);
void setContentLength(const size_t contentLength);
void sendHeader(const String& name, const String& value, bool first = false);
void sendContent(const String& content);
void sendContent_P(PGM_P content);
void sendContent_P(PGM_P content, size_t size);
static String urlDecode(const String& text);
template<typename T>
size_t streamFile(T &file, const String& contentType) {
_streamFileCore(file.size(), file.name(), contentType);
return _currentClient.write(file);
}
protected:
virtual size_t _currentClientWrite(const char* b, size_t l) { return _currentClient.write( b, l ); }
virtual size_t _currentClientWrite_P(PGM_P b, size_t l) { return _currentClient.write_P( b, l ); }
void _addRequestHandler(RequestHandler* handler);
void _handleRequest();
void _finalizeResponse();
bool _parseRequest(WiFiClient& client);
void _parseArguments(String data);
static String _responseCodeToString(int code);
bool _parseForm(WiFiClient& client, String boundary, uint32_t len);
bool _parseFormUploadAborted();
void _uploadWriteByte(uint8_t b);
uint8_t _uploadReadByte(WiFiClient& client);
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
bool _collectHeader(const char* headerName, const char* headerValue);
void _streamFileCore(const size_t fileSize, const String & fileName, const String & contentType);
String _getRandomHexString();
// for extracting Auth parameters
String _extractParam(String& authReq,const String& param,const char delimit = '"');
struct RequestArgument {
String key;
String value;
};
WiFiServer _server;
WiFiClient _currentClient;
HTTPMethod _currentMethod;
String _currentUri;
uint8_t _currentVersion;
HTTPClientStatus _currentStatus;
unsigned long _statusChange;
RequestHandler* _currentHandler;
RequestHandler* _firstHandler;
RequestHandler* _lastHandler;
THandlerFunction _notFoundHandler;
THandlerFunction _fileUploadHandler;
int _currentArgCount;
RequestArgument* _currentArgs;
std::unique_ptr<HTTPUpload> _currentUpload;
int _headerKeysCount;
RequestArgument* _currentHeaders;
size_t _contentLength;
String _responseHeaders;
String _hostHeader;
bool _chunked;
String _snonce; // Store noance and opaque for future comparison
String _sopaque;
String _srealm; // Store the Auth realm between Calls
};
#endif //ESP8266WEBSERVER_H

View File

@ -0,0 +1,19 @@
#ifndef REQUESTHANDLER_H
#define REQUESTHANDLER_H
class RequestHandler {
public:
virtual ~RequestHandler() { }
virtual bool canHandle(HTTPMethod method, String uri) { (void) method; (void) uri; return false; }
virtual bool canUpload(String uri) { (void) uri; return false; }
virtual bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) { (void) server; (void) requestMethod; (void) requestUri; return false; }
virtual void upload(WebServer& server, String requestUri, HTTPUpload& upload) { (void) server; (void) requestUri; (void) upload; }
RequestHandler* next() { return _next; }
void next(RequestHandler* r) { _next = r; }
private:
RequestHandler* _next = nullptr;
};
#endif //REQUESTHANDLER_H

View File

@ -0,0 +1,148 @@
#ifndef REQUESTHANDLERSIMPL_H
#define REQUESTHANDLERSIMPL_H
#include "RequestHandler.h"
#include "mimetable.h"
#include "WString.h"
using namespace mime;
class FunctionRequestHandler : public RequestHandler {
public:
FunctionRequestHandler(WebServer::THandlerFunction fn, WebServer::THandlerFunction ufn, const String &uri, HTTPMethod method)
: _fn(fn)
, _ufn(ufn)
, _uri(uri)
, _method(method)
{
}
bool canHandle(HTTPMethod requestMethod, String requestUri) override {
if (_method != HTTP_ANY && _method != requestMethod)
return false;
if (requestUri != _uri)
return false;
return true;
}
bool canUpload(String requestUri) override {
if (!_ufn || !canHandle(HTTP_POST, requestUri))
return false;
return true;
}
bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) override {
(void) server;
if (!canHandle(requestMethod, requestUri))
return false;
_fn();
return true;
}
void upload(WebServer& server, String requestUri, HTTPUpload& upload) override {
(void) server;
(void) upload;
if (canUpload(requestUri))
_ufn();
}
protected:
WebServer::THandlerFunction _fn;
WebServer::THandlerFunction _ufn;
String _uri;
HTTPMethod _method;
};
class StaticRequestHandler : public RequestHandler {
public:
StaticRequestHandler(FS& fs, const char* path, const char* uri, const char* cache_header)
: _fs(fs)
, _uri(uri)
, _path(path)
, _cache_header(cache_header)
{
_isFile = fs.exists(path);
log_v("StaticRequestHandler: path=%s uri=%s isFile=%d, cache_header=%s\r\n", path, uri, _isFile, cache_header);
_baseUriLength = _uri.length();
}
bool canHandle(HTTPMethod requestMethod, String requestUri) override {
if (requestMethod != HTTP_GET)
return false;
if ((_isFile && requestUri != _uri) || !requestUri.startsWith(_uri))
return false;
return true;
}
bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) override {
if (!canHandle(requestMethod, requestUri))
return false;
log_v("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str());
String path(_path);
if (!_isFile) {
// Base URI doesn't point to a file.
// If a directory is requested, look for index file.
if (requestUri.endsWith("/"))
requestUri += "index.htm";
// Append whatever follows this URI in request to get the file path.
path += requestUri.substring(_baseUriLength);
}
log_v("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile);
String contentType = getContentType(path);
// look for gz file, only if the original specified path is not a gz. So part only works to send gzip via content encoding when a non compressed is asked for
// if you point the the path to gzip you will serve the gzip as content type "application/x-gzip", not text or javascript etc...
if (!path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !_fs.exists(path)) {
String pathWithGz = path + FPSTR(mimeTable[gz].endsWith);
if(_fs.exists(pathWithGz))
path += FPSTR(mimeTable[gz].endsWith);
}
File f = _fs.open(path, "r");
if (!f)
return false;
if (_cache_header.length() != 0)
server.sendHeader("Cache-Control", _cache_header);
server.streamFile(f, contentType);
return true;
}
static String getContentType(const String& path) {
char buff[sizeof(mimeTable[0].mimeType)];
// Check all entries but last one for match, return if found
for (size_t i=0; i < sizeof(mimeTable)/sizeof(mimeTable[0])-1; i++) {
strcpy_P(buff, mimeTable[i].endsWith);
if (path.endsWith(buff)) {
strcpy_P(buff, mimeTable[i].mimeType);
return String(buff);
}
}
// Fall-through and just return default type
strcpy_P(buff, mimeTable[sizeof(mimeTable)/sizeof(mimeTable[0])-1].mimeType);
return String(buff);
}
protected:
FS _fs;
String _uri;
String _path;
String _cache_header;
bool _isFile;
size_t _baseUriLength;
};
#endif //REQUESTHANDLERSIMPL_H

View File

@ -0,0 +1,35 @@
#include "mimetable.h"
#include "pgmspace.h"
namespace mime
{
// Table of extension->MIME strings stored in PROGMEM, needs to be global due to GCC section typing rules
const Entry mimeTable[maxType] =
{
{ ".html", "text/html" },
{ ".htm", "text/html" },
{ ".css", "text/css" },
{ ".txt", "text/plain" },
{ ".js", "application/javascript" },
{ ".json", "application/json" },
{ ".png", "image/png" },
{ ".gif", "image/gif" },
{ ".jpg", "image/jpeg" },
{ ".ico", "image/x-icon" },
{ ".svg", "image/svg+xml" },
{ ".ttf", "application/x-font-ttf" },
{ ".otf", "application/x-font-opentype" },
{ ".woff", "application/font-woff" },
{ ".woff2", "application/font-woff2" },
{ ".eot", "application/vnd.ms-fontobject" },
{ ".sfnt", "application/font-sfnt" },
{ ".xml", "text/xml" },
{ ".pdf", "application/pdf" },
{ ".zip", "application/zip" },
{ ".gz", "application/x-gzip" },
{ ".appcache", "text/cache-manifest" },
{ "", "application/octet-stream" }
};
}

View File

@ -0,0 +1,47 @@
#ifndef __MIMETABLE_H__
#define __MIMETABLE_H__
namespace mime
{
enum type
{
html,
htm,
css,
txt,
js,
json,
png,
gif,
jpg,
ico,
svg,
ttf,
otf,
woff,
woff2,
eot,
sfnt,
xml,
pdf,
zip,
gz,
appcache,
none,
maxType
};
struct Entry
{
const char endsWith[16];
const char mimeType[32];
};
extern const Entry mimeTable[maxType];
}
#endif

View File

@ -16,16 +16,28 @@ Pranav Cherukupalli <cherukupallip@gmail.com>
#include "WiFi.h"
#include "esp_wps.h"
/*
Change the definition of the WPS mode
from WPS_TYPE_PBC to WPS_TYPE_PIN in
the case that you are using pin type
WPS
*/
#define ESP_WPS_MODE WPS_TYPE_PBC
#define ESP_WPS_MODE WPS_TYPE_PBC
#define ESP_MANUFACTURER "ESPRESSIF"
#define ESP_MODEL_NUMBER "ESP32"
#define ESP_MODEL_NAME "ESPRESSIF IOT"
#define ESP_DEVICE_NAME "ESP STATION"
esp_wps_config_t config = WPS_CONFIG_INIT_DEFAULT(ESP_WPS_MODE);
static esp_wps_config_t config;
void wpsInitConfig(){
config.crypto_funcs = &g_wifi_default_wps_crypto_funcs;
config.wps_type = ESP_WPS_MODE;
strcpy(config.factory_info.manufacturer, ESP_MANUFACTURER);
strcpy(config.factory_info.model_number, ESP_MODEL_NUMBER);
strcpy(config.factory_info.model_name, ESP_MODEL_NAME);
strcpy(config.factory_info.device_name, ESP_DEVICE_NAME);
}
String wpspin2string(uint8_t a[]){
char wps_pin[9];
@ -39,40 +51,40 @@ String wpspin2string(uint8_t a[]){
void WiFiEvent(WiFiEvent_t event, system_event_info_t info){
switch(event){
case SYSTEM_EVENT_STA_START:
Serial.println("Station Mode Started");
break;
Serial.println("Station Mode Started");
break;
case SYSTEM_EVENT_STA_GOT_IP:
Serial.println("Connected to :" + String(WiFi.SSID()));
Serial.print("Got IP: ");
Serial.println(WiFi.localIP());
break;
Serial.println("Connected to :" + String(WiFi.SSID()));
Serial.print("Got IP: ");
Serial.println(WiFi.localIP());
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
Serial.println("Disconnected from station, attempting reconnection");
WiFi.reconnect();
break;
Serial.println("Disconnected from station, attempting reconnection");
WiFi.reconnect();
break;
case SYSTEM_EVENT_STA_WPS_ER_SUCCESS:
Serial.println("WPS Successfull, stopping WPS and connecting to: " + String(WiFi.SSID()));
esp_wifi_wps_disable();
delay(10);
WiFi.begin();
break;
Serial.println("WPS Successfull, stopping WPS and connecting to: " + String(WiFi.SSID()));
esp_wifi_wps_disable();
delay(10);
WiFi.begin();
break;
case SYSTEM_EVENT_STA_WPS_ER_FAILED:
Serial.println("WPS Failed, retrying");
esp_wifi_wps_disable();
esp_wifi_wps_enable(&config);
esp_wifi_wps_start(0);
break;
Serial.println("WPS Failed, retrying");
esp_wifi_wps_disable();
esp_wifi_wps_enable(&config);
esp_wifi_wps_start(0);
break;
case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT:
Serial.println("WPS Timedout, retrying");
esp_wifi_wps_disable();
esp_wifi_wps_enable(&config);
esp_wifi_wps_start(0);
break;
Serial.println("WPS Timedout, retrying");
esp_wifi_wps_disable();
esp_wifi_wps_enable(&config);
esp_wifi_wps_start(0);
break;
case SYSTEM_EVENT_STA_WPS_ER_PIN:
Serial.println("WPS_PIN = " + wpspin2string(info.sta_er_pin.pin_code));
break;
Serial.println("WPS_PIN = " + wpspin2string(info.sta_er_pin.pin_code));
break;
default:
break;
break;
}
}
@ -87,10 +99,11 @@ void setup(){
Serial.println("Starting WPS");
wpsInitConfig();
esp_wifi_wps_enable(&config);
esp_wifi_wps_start(0);
}
void loop(){
//nothing to do here
}
}

View File

@ -56,9 +56,6 @@ void WiFiClass::printDiag(Print& p)
wifi_second_chan_t secondChan;
esp_wifi_get_channel(&primaryChan, &secondChan);
bool autoConnect;
esp_wifi_get_auto_connect(&autoConnect);
p.print("Mode: ");
p.println(modes[mode]);
@ -71,8 +68,6 @@ void WiFiClass::printDiag(Print& p)
p.print("Status: ");
p.println(wifi_station_get_connect_status());
*/
p.print("Auto connect: ");
p.println(autoConnect);
wifi_config_t conf;
esp_wifi_get_config(WIFI_IF_STA, &conf);

View File

@ -18,6 +18,7 @@
*/
#include "WiFiClient.h"
#include "WiFi.h"
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include <errno.h>
@ -105,12 +106,10 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
int WiFiClient::connect(const char *host, uint16_t port)
{
struct hostent *server;
server = gethostbyname(host);
if (server == NULL) {
IPAddress srv((uint32_t)0);
if(!WiFiGenericClass::hostByName(host, srv)){
return 0;
}
IPAddress srv((const uint8_t *)(server->h_addr));
return connect(srv, port);
}
@ -241,6 +240,24 @@ size_t WiFiClient::write_P(PGM_P buf, size_t size)
return write(buf, size);
}
size_t WiFiClient::write(Stream &stream)
{
uint8_t * buf = (uint8_t *)malloc(1360);
if(!buf){
return 0;
}
size_t toRead = 0, toWrite = 0, written = 0;
size_t available = stream.available();
while(available){
toRead = (available > 1360)?1360:available;
toWrite = stream.readBytes(buf, toRead);
written += write(buf, toWrite);
available = stream.available();
}
free(buf);
return written;
}
int WiFiClient::read(uint8_t *buf, size_t size)
{
if(!available()) {

View File

@ -45,6 +45,7 @@ public:
size_t write(uint8_t data);
size_t write(const uint8_t *buf, size_t size);
size_t write_P(PGM_P buf, size_t size);
size_t write(Stream &stream);
int available();
int read();
int read(uint8_t *buf, size_t size);

View File

@ -61,6 +61,7 @@ extern "C" {
static xQueueHandle _network_event_queue;
static TaskHandle_t _network_event_task_handle = NULL;
static EventGroupHandle_t _network_event_group = NULL;
static void _network_event_task(void * arg){
system_event_t *event = NULL;
@ -81,35 +82,42 @@ static esp_err_t _network_event_cb(void *arg, system_event_t *event){
return ESP_OK;
}
static void _start_network_event_task(){
static bool _start_network_event_task(){
if(!_network_event_group){
_network_event_group = xEventGroupCreate();
if(!_network_event_group){
log_e("Network Event Group Create Failed!");
return false;
}
xEventGroupSetBits(_network_event_group, WIFI_DNS_IDLE_BIT);
}
if(!_network_event_queue){
_network_event_queue = xQueueCreate(32, sizeof(system_event_t *));
if(!_network_event_queue){
log_e("Network Event Queue Create Failed!");
return;
return false;
}
}
if(!_network_event_task_handle){
xTaskCreatePinnedToCore(_network_event_task, "network_event", 4096, NULL, 2, &_network_event_task_handle, ARDUINO_RUNNING_CORE);
if(!_network_event_task_handle){
log_e("Network Event Task Start Failed!");
return;
return false;
}
}
esp_event_loop_init(&_network_event_cb, NULL);
return esp_event_loop_init(&_network_event_cb, NULL) == ESP_OK;
}
void tcpipInit(){
static bool initialized = false;
if(!initialized){
if(!initialized && _start_network_event_task()){
initialized = true;
_start_network_event_task();
tcpip_adapter_init();
}
}
static bool lowLevelInitDone = false;
static bool wifiLowLevelInit(bool persistent){
static bool lowLevelInitDone = false;
if(!lowLevelInitDone){
tcpipInit();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
@ -121,7 +129,6 @@ static bool wifiLowLevelInit(bool persistent){
if(!persistent){
esp_wifi_set_storage(WIFI_STORAGE_RAM);
}
esp_wifi_set_mode(WIFI_MODE_NULL);
lowLevelInitDone = true;
}
return true;
@ -161,12 +168,13 @@ static bool espWiFiStop(){
if(!_esp_wifi_started){
return true;
}
_esp_wifi_started = false;
err = esp_wifi_stop();
if(err){
log_e("Could not stop WiFi! %u", err);
_esp_wifi_started = true;
return false;
}
_esp_wifi_started = false;
return wifiLowLevelDeinit();
}
@ -198,6 +206,39 @@ WiFiGenericClass::WiFiGenericClass()
}
int WiFiGenericClass::setStatusBits(int bits){
if(!_network_event_group){
return 0;
}
return xEventGroupSetBits(_network_event_group, bits);
}
int WiFiGenericClass::clearStatusBits(int bits){
if(!_network_event_group){
return 0;
}
return xEventGroupClearBits(_network_event_group, bits);
}
int WiFiGenericClass::getStatusBits(){
if(!_network_event_group){
return 0;
}
return xEventGroupGetBits(_network_event_group);
}
int WiFiGenericClass::waitStatusBits(int bits, uint32_t timeout_ms){
if(!_network_event_group){
return 0;
}
return xEventGroupWaitBits(
_network_event_group, // The event group being tested.
bits, // The bits within the event group to wait for.
pdFALSE, // BIT_0 and BIT_4 should be cleared before returning.
pdTRUE, // Don't wait for both bits, either bit will do.
timeout_ms / portTICK_PERIOD_MS ) & bits; // Wait a maximum of 100ms for either bit to be set.
}
/**
* set callback function
* @param cbEvent WiFiEventCb
@ -304,6 +345,16 @@ esp_err_t WiFiGenericClass::_eventCallback(void *arg, system_event_t *event)
log_d("Event: %d - %s", event->event_id, system_event_names[event->event_id]);
if(event->event_id == SYSTEM_EVENT_SCAN_DONE) {
WiFiScanClass::_scanDone();
} else if(event->event_id == SYSTEM_EVENT_STA_START) {
WiFiSTAClass::_setStatus(WL_DISCONNECTED);
setStatusBits(STA_STARTED_BIT);
} else if(event->event_id == SYSTEM_EVENT_STA_STOP) {
WiFiSTAClass::_setStatus(WL_NO_SHIELD);
clearStatusBits(STA_STARTED_BIT | STA_CONNECTED_BIT | STA_HAS_IP_BIT | STA_HAS_IP6_BIT);
} else if(event->event_id == SYSTEM_EVENT_STA_CONNECTED) {
WiFiSTAClass::_setStatus(WL_IDLE_STATUS);
setStatusBits(STA_CONNECTED_BIT);
} else if(event->event_id == SYSTEM_EVENT_STA_DISCONNECTED) {
uint8_t reason = event->event_info.disconnected.reason;
log_w("Reason: %u - %s", reason, reason2str(reason));
@ -320,17 +371,47 @@ esp_err_t WiFiGenericClass::_eventCallback(void *arg, system_event_t *event)
} else {
WiFiSTAClass::_setStatus(WL_DISCONNECTED);
}
} else if(event->event_id == SYSTEM_EVENT_STA_START) {
WiFiSTAClass::_setStatus(WL_DISCONNECTED);
} else if(event->event_id == SYSTEM_EVENT_STA_STOP) {
WiFiSTAClass::_setStatus(WL_NO_SHIELD);
} else if(event->event_id == SYSTEM_EVENT_STA_CONNECTED) {
WiFiSTAClass::_setStatus(WL_IDLE_STATUS);
clearStatusBits(STA_CONNECTED_BIT | STA_HAS_IP_BIT | STA_HAS_IP6_BIT);
if(reason >= WIFI_REASON_BEACON_TIMEOUT && reason != WIFI_REASON_AUTH_FAIL && WiFi.getAutoReconnect()){
WiFi.begin();
}
} else if(event->event_id == SYSTEM_EVENT_STA_GOT_IP) {
//#1081 https://github.com/espressif/arduino-esp32/issues/1081
// if(WiFiSTAClass::status() == WL_IDLE_STATUS)
{
WiFiSTAClass::_setStatus(WL_CONNECTED);
WiFiSTAClass::_setStatus(WL_CONNECTED);
setStatusBits(STA_HAS_IP_BIT | STA_CONNECTED_BIT);
} else if(event->event_id == SYSTEM_EVENT_STA_LOST_IP) {
WiFiSTAClass::_setStatus(WL_IDLE_STATUS);
clearStatusBits(STA_HAS_IP_BIT);
} else if(event->event_id == SYSTEM_EVENT_AP_START) {
setStatusBits(AP_STARTED_BIT);
} else if(event->event_id == SYSTEM_EVENT_AP_STOP) {
clearStatusBits(AP_STARTED_BIT | AP_HAS_CLIENT_BIT);
} else if(event->event_id == SYSTEM_EVENT_AP_STACONNECTED) {
setStatusBits(AP_HAS_CLIENT_BIT);
} else if(event->event_id == SYSTEM_EVENT_AP_STADISCONNECTED) {
wifi_sta_list_t clients;
if(esp_wifi_ap_get_sta_list(&clients) != ESP_OK || !clients.num){
clearStatusBits(AP_HAS_CLIENT_BIT);
}
} else if(event->event_id == SYSTEM_EVENT_ETH_START) {
setStatusBits(ETH_STARTED_BIT);
} else if(event->event_id == SYSTEM_EVENT_ETH_STOP) {
clearStatusBits(ETH_STARTED_BIT | ETH_CONNECTED_BIT | ETH_HAS_IP_BIT | ETH_HAS_IP6_BIT);
} else if(event->event_id == SYSTEM_EVENT_ETH_CONNECTED) {
setStatusBits(ETH_CONNECTED_BIT);
} else if(event->event_id == SYSTEM_EVENT_ETH_DISCONNECTED) {
clearStatusBits(ETH_CONNECTED_BIT | ETH_HAS_IP_BIT | ETH_HAS_IP6_BIT);
} else if(event->event_id == SYSTEM_EVENT_ETH_GOT_IP) {
setStatusBits(ETH_CONNECTED_BIT | ETH_HAS_IP_BIT);
} else if(event->event_id == SYSTEM_EVENT_GOT_IP6) {
if(event->event_info.got_ip6.if_index == TCPIP_ADAPTER_IF_AP){
setStatusBits(AP_HAS_IP6_BIT);
} else if(event->event_info.got_ip6.if_index == TCPIP_ADAPTER_IF_STA){
setStatusBits(STA_CONNECTED_BIT | STA_HAS_IP6_BIT);
} else if(event->event_info.got_ip6.if_index == TCPIP_ADAPTER_IF_ETH){
setStatusBits(ETH_CONNECTED_BIT | ETH_HAS_IP6_BIT);
}
}
@ -357,8 +438,11 @@ esp_err_t WiFiGenericClass::_eventCallback(void *arg, system_event_t *event)
*/
int32_t WiFiGenericClass::channel(void)
{
uint8_t primaryChan;
wifi_second_chan_t secondChan;
uint8_t primaryChan = 0;
wifi_second_chan_t secondChan = WIFI_SECOND_CHAN_NONE;
if(!lowLevelInitDone){
return primaryChan;
}
esp_wifi_get_channel(&primaryChan, &secondChan);
return primaryChan;
}
@ -380,19 +464,15 @@ void WiFiGenericClass::persistent(bool persistent)
*/
bool WiFiGenericClass::mode(wifi_mode_t m)
{
if (!_esp_wifi_started) {
wifiLowLevelInit(_persistent);
}
wifi_mode_t cm = getMode();
if(cm == WIFI_MODE_MAX){
return false;
}
if(cm == m) {
return true;
}
if(m){
espWiFiStart(_persistent);
} else {
if(!cm && m){
if(!espWiFiStart(_persistent)){
return false;
}
} else if(cm && !m){
return espWiFiStop();
}
@ -402,10 +482,7 @@ bool WiFiGenericClass::mode(wifi_mode_t m)
log_e("Could not set mode! %u", err);
return false;
}
if(m){
return espWiFiStart(_persistent);
}
return espWiFiStop();
return true;
}
/**
@ -414,13 +491,15 @@ bool WiFiGenericClass::mode(wifi_mode_t m)
*/
wifi_mode_t WiFiGenericClass::getMode()
{
if(!wifiLowLevelInit(_persistent)){
return WIFI_MODE_MAX;
if(!_esp_wifi_started){
return WIFI_MODE_NULL;
}
uint8_t mode;
esp_wifi_get_mode((wifi_mode_t*)&mode);
return (wifi_mode_t)mode;
wifi_mode_t mode;
if(esp_wifi_get_mode(&mode) == ESP_ERR_WIFI_NOT_INIT){
log_w("WiFi not started");
return WIFI_MODE_NULL;
}
return mode;
}
/**
@ -437,12 +516,10 @@ bool WiFiGenericClass::enableSTA(bool enable)
if(isEnabled != enable) {
if(enable) {
return mode((wifi_mode_t)(currentMode | WIFI_MODE_STA));
} else {
return mode((wifi_mode_t)(currentMode & (~WIFI_MODE_STA)));
}
} else {
return true;
return mode((wifi_mode_t)(currentMode & (~WIFI_MODE_STA)));
}
return true;
}
/**
@ -459,21 +536,72 @@ bool WiFiGenericClass::enableAP(bool enable)
if(isEnabled != enable) {
if(enable) {
return mode((wifi_mode_t)(currentMode | WIFI_MODE_AP));
} else {
return mode((wifi_mode_t)(currentMode & (~WIFI_MODE_AP)));
}
} else {
return true;
return mode((wifi_mode_t)(currentMode & (~WIFI_MODE_AP)));
}
return true;
}
/**
* control modem sleep when only in STA mode
* @param enable bool
* @return ok
*/
bool WiFiGenericClass::setSleep(bool enable)
{
if((getMode() & WIFI_MODE_STA) == 0){
log_w("STA has not been started");
return false;
}
return esp_wifi_set_ps(enable?WIFI_PS_MIN_MODEM:WIFI_PS_NONE) == ESP_OK;
}
/**
* get modem sleep enabled
* @return true if modem sleep is enabled
*/
bool WiFiGenericClass::getSleep()
{
wifi_ps_type_t ps;
if((getMode() & WIFI_MODE_STA) == 0){
log_w("STA has not been started");
return false;
}
if(esp_wifi_get_ps(&ps) == ESP_OK){
return ps == WIFI_PS_MIN_MODEM;
}
return false;
}
/**
* control wifi tx power
* @param power enum maximum wifi tx power
* @return ok
*/
bool WiFiGenericClass::setTxPower(wifi_power_t power){
if((getStatusBits() & (STA_STARTED_BIT | AP_STARTED_BIT)) == 0){
log_w("Neither AP or STA has been started");
return false;
}
return esp_wifi_set_max_tx_power(power) == ESP_OK;
}
wifi_power_t WiFiGenericClass::getTxPower(){
int8_t power;
if((getStatusBits() & (STA_STARTED_BIT | AP_STARTED_BIT)) == 0){
log_w("Neither AP or STA has been started");
return WIFI_POWER_19_5dBm;
}
if(esp_wifi_get_max_tx_power(&power)){
return WIFI_POWER_19_5dBm;
}
return (wifi_power_t)power;
}
// -----------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------ Generic Network function ---------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
static bool _dns_busy = false;
/**
* DNS callback
* @param name
@ -485,7 +613,7 @@ static void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, v
if(ipaddr) {
(*reinterpret_cast<IPAddress*>(callback_arg)) = ipaddr->u_addr.ip4.addr;
}
_dns_busy = false;
xEventGroupSetBits(_network_event_group, WIFI_DNS_DONE_BIT);
}
/**
@ -499,20 +627,19 @@ int WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult)
{
ip_addr_t addr;
aResult = static_cast<uint32_t>(0);
_dns_busy = true;
waitStatusBits(WIFI_DNS_IDLE_BIT, 5000);
clearStatusBits(WIFI_DNS_IDLE_BIT);
err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &aResult);
if(err == ERR_OK && addr.u_addr.ip4.addr) {
aResult = addr.u_addr.ip4.addr;
_dns_busy = false;
} else if(err == ERR_INPROGRESS) {
while(_dns_busy){
delay(1);
}
} else {
_dns_busy = false;
return 0;
waitStatusBits(WIFI_DNS_DONE_BIT, 4000);
clearStatusBits(WIFI_DNS_DONE_BIT);
}
return 1;
setStatusBits(WIFI_DNS_IDLE_BIT);
if((uint32_t)aResult == 0){
log_e("DNS Failed for %s", aHostname);
}
return (uint32_t)aResult != 0;
}

View File

@ -34,6 +34,37 @@ typedef void (*WiFiEventSysCb)(system_event_t *event);
typedef size_t wifi_event_id_t;
typedef enum {
WIFI_POWER_19_5dBm = 78,// 19.5dBm
WIFI_POWER_19dBm = 76,// 19dBm
WIFI_POWER_18_5dBm = 74,// 18.5dBm
WIFI_POWER_17dBm = 68,// 17dBm
WIFI_POWER_15dBm = 60,// 15dBm
WIFI_POWER_13dBm = 52,// 13dBm
WIFI_POWER_11dBm = 44,// 11dBm
WIFI_POWER_8_5dBm = 34,// 8.5dBm
WIFI_POWER_7dBm = 28,// 7dBm
WIFI_POWER_5dBm = 20,// 5dBm
WIFI_POWER_2dBm = 8,// 2dBm
WIFI_POWER_MINUS_1dBm = -4// -1dBm
} wifi_power_t;
static const int AP_STARTED_BIT = BIT0;
static const int AP_HAS_IP6_BIT = BIT1;
static const int AP_HAS_CLIENT_BIT = BIT2;
static const int STA_STARTED_BIT = BIT3;
static const int STA_CONNECTED_BIT = BIT4;
static const int STA_HAS_IP_BIT = BIT5;
static const int STA_HAS_IP6_BIT = BIT6;
static const int ETH_STARTED_BIT = BIT7;
static const int ETH_CONNECTED_BIT = BIT8;
static const int ETH_HAS_IP_BIT = BIT9;
static const int ETH_HAS_IP6_BIT = BIT10;
static const int WIFI_SCANNING_BIT = BIT11;
static const int WIFI_SCAN_DONE_BIT= BIT12;
static const int WIFI_DNS_IDLE_BIT = BIT13;
static const int WIFI_DNS_DONE_BIT = BIT14;
class WiFiGenericClass
{
public:
@ -46,6 +77,9 @@ class WiFiGenericClass
void removeEvent(WiFiEventSysCb cbEvent, system_event_id_t event = SYSTEM_EVENT_MAX);
void removeEvent(wifi_event_id_t id);
static int getStatusBits();
static int waitStatusBits(int bits, uint32_t timeout_ms);
int32_t channel(void);
void persistent(bool persistent);
@ -56,14 +90,23 @@ class WiFiGenericClass
bool enableSTA(bool enable);
bool enableAP(bool enable);
bool setSleep(bool enable);
bool getSleep();
bool setTxPower(wifi_power_t power);
wifi_power_t getTxPower();
static esp_err_t _eventCallback(void *arg, system_event_t *event);
protected:
static bool _persistent;
static wifi_mode_t _forceSleepLastMode;
static int setStatusBits(int bits);
static int clearStatusBits(int bits);
public:
int hostByName(const char *aHostname, IPAddress &aResult);
static int hostByName(const char *aHostname, IPAddress &aResult);
protected:
friend class WiFiSTAClass;

View File

@ -59,24 +59,9 @@ static bool sta_config_equal(const wifi_config_t& lhs, const wifi_config_t& rhs)
*/
static bool sta_config_equal(const wifi_config_t& lhs, const wifi_config_t& rhs)
{
if(strcmp(reinterpret_cast<const char*>(lhs.sta.ssid), reinterpret_cast<const char*>(rhs.sta.ssid)) != 0) {
if(memcmp(&lhs, &rhs, sizeof(wifi_config_t)) != 0) {
return false;
}
if(strcmp(reinterpret_cast<const char*>(lhs.sta.password), reinterpret_cast<const char*>(rhs.sta.password)) != 0) {
return false;
}
if(lhs.sta.bssid_set != rhs.sta.bssid_set) {
return false;
}
if(lhs.sta.bssid_set) {
if(memcmp(lhs.sta.bssid, rhs.sta.bssid, 6) != 0) {
return false;
}
}
return true;
}
@ -86,7 +71,37 @@ static bool sta_config_equal(const wifi_config_t& lhs, const wifi_config_t& rhs)
bool WiFiSTAClass::_autoReconnect = true;
bool WiFiSTAClass::_useStaticIp = false;
wl_status_t WiFiSTAClass::_status = WL_NO_SHIELD;
static wl_status_t _sta_status = WL_NO_SHIELD;
static EventGroupHandle_t _sta_status_group = NULL;
void WiFiSTAClass::_setStatus(wl_status_t status)
{
if(!_sta_status_group){
_sta_status_group = xEventGroupCreate();
if(!_sta_status_group){
log_e("STA Status Group Create Failed!");
_sta_status = status;
return;
}
}
xEventGroupClearBits(_sta_status_group, 0x00FFFFFF);
xEventGroupSetBits(_sta_status_group, status);
}
/**
* Return Connection status.
* @return one of the value defined in wl_status_t
*
*/
wl_status_t WiFiSTAClass::status()
{
if(!_sta_status_group){
return _sta_status;
}
return (wl_status_t)xEventGroupClearBits(_sta_status_group, 0);
}
/**
* Start Wifi connection
* if passphrase is set the most secure supported mode will be automatically selected
@ -101,60 +116,68 @@ wl_status_t WiFiSTAClass::begin(const char* ssid, const char *passphrase, int32_
{
if(!WiFi.enableSTA(true)) {
// enable STA failed
log_e("STA enable failed!");
return WL_CONNECT_FAILED;
}
if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) {
// fail SSID too long or missing!
log_e("SSID too long or missing!");
return WL_CONNECT_FAILED;
}
if(passphrase && strlen(passphrase) > 64) {
// fail passphrase too long!
log_e("passphrase too long!");
return WL_CONNECT_FAILED;
}
wifi_config_t conf;
memset(&conf, 0, sizeof(wifi_config_t));
strcpy(reinterpret_cast<char*>(conf.sta.ssid), ssid);
if(passphrase) {
if (strlen(passphrase) == 64) // it's not a passphrase, is the PSK
if (strlen(passphrase) == 64){ // it's not a passphrase, is the PSK
memcpy(reinterpret_cast<char*>(conf.sta.password), passphrase, 64);
else
} else {
strcpy(reinterpret_cast<char*>(conf.sta.password), passphrase);
} else {
*conf.sta.password = 0;
}
}
if(bssid) {
conf.sta.bssid_set = 1;
memcpy((void *) &conf.sta.bssid[0], (void *) bssid, 6);
} else {
conf.sta.bssid_set = 0;
}
if(channel > 0 && channel <= 13) {
conf.sta.channel = channel;
}
wifi_config_t current_conf;
esp_wifi_get_config(WIFI_IF_STA, &current_conf);
if(!sta_config_equal(current_conf, conf)) {
if(esp_wifi_disconnect()){
log_e("disconnect failed!");
return WL_CONNECT_FAILED;
}
esp_wifi_set_config(WIFI_IF_STA, &conf);
}
if(channel > 0 && channel <= 13) {
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
}
esp_wifi_start();
if(connect) {
esp_wifi_connect();
} else if(status() == WL_CONNECTED){
return WL_CONNECTED;
}
if(!_useStaticIp) {
tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA);
if(tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA) == ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED){
log_e("dhcp client start failed!");
return WL_CONNECT_FAILED;
}
} else {
tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA);
}
if(connect && esp_wifi_connect()) {
log_e("connect failed!");
return WL_CONNECT_FAILED;
}
return status();
}
@ -171,25 +194,68 @@ wl_status_t WiFiSTAClass::begin()
{
if(!WiFi.enableSTA(true)) {
// enable STA failed
log_e("STA enable failed!");
return WL_CONNECT_FAILED;
}
esp_wifi_start();
esp_wifi_connect();
if(!_useStaticIp) {
tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA);
if(tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA) == ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED){
log_e("dhcp client start failed!");
return WL_CONNECT_FAILED;
}
} else {
tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA);
}
if(status() != WL_CONNECTED && esp_wifi_connect()){
log_e("connect failed!");
return WL_CONNECT_FAILED;
}
return status();
}
void WiFiSTAClass::_setStatus(wl_status_t status)
/**
* will force a disconnect an then start reconnecting to AP
* @return ok
*/
bool WiFiSTAClass::reconnect()
{
_status = status;
//log_i("wifi status: %d", status);
if(WiFi.getMode() & WIFI_MODE_STA) {
if(esp_wifi_disconnect() == ESP_OK) {
return esp_wifi_connect() == ESP_OK;
}
}
return false;
}
/**
* Disconnect from the network
* @param wifioff
* @return one value of wl_status_t enum
*/
bool WiFiSTAClass::disconnect(bool wifioff, bool eraseap)
{
wifi_config_t conf;
if(WiFi.getMode() & WIFI_MODE_STA){
if(eraseap){
memset(&conf, 0, sizeof(wifi_config_t));
if(esp_wifi_set_config(WIFI_IF_STA, &conf)){
log_e("clear config failed!");
}
}
if(esp_wifi_disconnect()){
log_e("disconnect failed!");
return false;
}
if(wifioff) {
return WiFi.enableSTA(false);
}
return true;
}
return false;
}
/**
@ -207,7 +273,6 @@ bool WiFiSTAClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subne
if(!WiFi.enableSTA(true)) {
return false;
}
esp_wifi_start();
tcpip_adapter_ip_info_t info;
@ -237,8 +302,8 @@ bool WiFiSTAClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subne
_useStaticIp = true;
} else {
err = tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA);
if(err != ESP_OK && err != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STARTED){
log_w("DHCP could not be started! Error: %d", err);
if(err == ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED){
log_e("dhcp client start failed!");
return false;
}
_useStaticIp = false;
@ -262,44 +327,6 @@ bool WiFiSTAClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subne
return true;
}
/**
* will force a disconnect an then start reconnecting to AP
* @return ok
*/
bool WiFiSTAClass::reconnect()
{
if((WiFi.getMode() & WIFI_MODE_STA) != 0) {
if(esp_wifi_disconnect() == ESP_OK) {
return esp_wifi_connect() == ESP_OK;
}
}
return false;
}
/**
* Disconnect from the network
* @param wifioff
* @return one value of wl_status_t enum
*/
bool WiFiSTAClass::disconnect(bool wifioff)
{
bool ret;
wifi_config_t conf;
*conf.sta.ssid = 0;
*conf.sta.password = 0;
WiFi.getMode();
esp_wifi_start();
esp_wifi_set_config(WIFI_IF_STA, &conf);
ret = esp_wifi_disconnect() == ESP_OK;
if(wifioff) {
WiFi.enableSTA(false);
}
return ret;
}
/**
* is STA interface connected?
* @return true if STA is connected to an AD
@ -318,9 +345,10 @@ bool WiFiSTAClass::isConnected()
*/
bool WiFiSTAClass::setAutoConnect(bool autoConnect)
{
bool ret;
/*bool ret;
ret = esp_wifi_set_auto_connect(autoConnect);
return ret;
return ret;*/
return false;//now deprecated
}
/**
@ -330,9 +358,10 @@ bool WiFiSTAClass::setAutoConnect(bool autoConnect)
*/
bool WiFiSTAClass::getAutoConnect()
{
bool autoConnect;
/*bool autoConnect;
esp_wifi_get_auto_connect(&autoConnect);
return autoConnect;
return autoConnect;*/
return false;//now deprecated
}
bool WiFiSTAClass::setAutoReconnect(bool autoReconnect)
@ -434,16 +463,6 @@ IPAddress WiFiSTAClass::dnsIP(uint8_t dns_no)
return IPAddress(dns_ip.u_addr.ip4.addr);
}
/**
* Return Connection status.
* @return one of the value defined in wl_status_t
*
*/
wl_status_t WiFiSTAClass::status()
{
return WiFiSTAClass::_status;
}
/**
* Return the current SSID associated with the network
* @return SSID

View File

@ -43,7 +43,7 @@ public:
bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000);
bool reconnect();
bool disconnect(bool wifioff = false);
bool disconnect(bool wifioff = false, bool eraseap = false);
bool isConnected();
@ -83,7 +83,6 @@ public:
static void _setStatus(wl_status_t status);
protected:
static wl_status_t _status;
static bool _useStaticIp;
static bool _autoReconnect;

View File

@ -42,8 +42,6 @@ extern "C" {
}
bool WiFiScanClass::_scanAsync = false;
bool WiFiScanClass::_scanStarted = false;
bool WiFiScanClass::_scanComplete = false;
uint16_t WiFiScanClass::_scanCount = 0;
void* WiFiScanClass::_scanResult = 0;
@ -56,7 +54,7 @@ void* WiFiScanClass::_scanResult = 0;
*/
int16_t WiFiScanClass::scanNetworks(bool async, bool show_hidden, bool passive, uint32_t max_ms_per_chan)
{
if(WiFiScanClass::_scanStarted) {
if(WiFiGenericClass::getStatusBits() & WIFI_SCANNING_BIT) {
return WIFI_SCAN_RUNNING;
}
@ -80,20 +78,17 @@ int16_t WiFiScanClass::scanNetworks(bool async, bool show_hidden, bool passive,
config.scan_time.active.max = max_ms_per_chan;
}
if(esp_wifi_scan_start(&config, false) == ESP_OK) {
WiFiScanClass::_scanComplete = false;
WiFiScanClass::_scanStarted = true;
WiFiGenericClass::clearStatusBits(WIFI_SCAN_DONE_BIT);
WiFiGenericClass::setStatusBits(WIFI_SCANNING_BIT);
if(WiFiScanClass::_scanAsync) {
return WIFI_SCAN_RUNNING;
}
while(!(WiFiScanClass::_scanComplete)) {
delay(10);
if(WiFiGenericClass::waitStatusBits(WIFI_SCAN_DONE_BIT, 10000)){
return (int16_t) WiFiScanClass::_scanCount;
}
return (int16_t) WiFiScanClass::_scanCount;
} else {
return WIFI_SCAN_FAILED;
}
return WIFI_SCAN_FAILED;
}
@ -105,18 +100,15 @@ int16_t WiFiScanClass::scanNetworks(bool async, bool show_hidden, bool passive,
*/
void WiFiScanClass::_scanDone()
{
WiFiScanClass::_scanComplete = true;
WiFiScanClass::_scanStarted = false;
esp_wifi_scan_get_ap_num(&(WiFiScanClass::_scanCount));
if(WiFiScanClass::_scanCount) {
WiFiScanClass::_scanResult = new wifi_ap_record_t[WiFiScanClass::_scanCount];
if(WiFiScanClass::_scanResult) {
esp_wifi_scan_get_ap_records(&(WiFiScanClass::_scanCount), (wifi_ap_record_t*)_scanResult);
} else {
//no memory
if(!WiFiScanClass::_scanResult || esp_wifi_scan_get_ap_records(&(WiFiScanClass::_scanCount), (wifi_ap_record_t*)_scanResult) != ESP_OK) {
WiFiScanClass::_scanCount = 0;
}
}
WiFiGenericClass::setStatusBits(WIFI_SCAN_DONE_BIT);
WiFiGenericClass::clearStatusBits(WIFI_SCANNING_BIT);
}
/**
@ -126,7 +118,7 @@ void WiFiScanClass::_scanDone()
*/
void * WiFiScanClass::_getScanInfoByIndex(int i)
{
if(!WiFiScanClass::_scanResult || (size_t) i > WiFiScanClass::_scanCount) {
if(!WiFiScanClass::_scanResult || (size_t) i >= WiFiScanClass::_scanCount) {
return 0;
}
return reinterpret_cast<wifi_ap_record_t*>(WiFiScanClass::_scanResult) + i;
@ -138,15 +130,14 @@ void * WiFiScanClass::_getScanInfoByIndex(int i)
* -1 if scan not fin
* -2 if scan not triggered
*/
int8_t WiFiScanClass::scanComplete()
int16_t WiFiScanClass::scanComplete()
{
if(_scanStarted) {
return WIFI_SCAN_RUNNING;
if(WiFiGenericClass::getStatusBits() & WIFI_SCAN_DONE_BIT) {
return WiFiScanClass::_scanCount;
}
if(_scanComplete) {
return WiFiScanClass::_scanCount;
if(WiFiGenericClass::getStatusBits() & WIFI_SCANNING_BIT) {
return WIFI_SCAN_RUNNING;
}
return WIFI_SCAN_FAILED;
@ -157,12 +148,12 @@ int8_t WiFiScanClass::scanComplete()
*/
void WiFiScanClass::scanDelete()
{
WiFiGenericClass::clearStatusBits(WIFI_SCAN_DONE_BIT);
if(WiFiScanClass::_scanResult) {
delete[] reinterpret_cast<wifi_ap_record_t*>(WiFiScanClass::_scanResult);
WiFiScanClass::_scanResult = 0;
WiFiScanClass::_scanCount = 0;
}
_scanComplete = false;
}

View File

@ -33,7 +33,7 @@ public:
int16_t scanNetworks(bool async = false, bool show_hidden = false, bool passive = false, uint32_t max_ms_per_chan = 300);
int8_t scanComplete();
int16_t scanComplete();
void scanDelete();
// scan result
@ -50,8 +50,6 @@ public:
protected:
static bool _scanAsync;
static bool _scanStarted;
static bool _scanComplete;
static uint16_t _scanCount;
static void* _scanResult;

View File

@ -62,9 +62,12 @@ WiFiClient WiFiServer::available(){
return WiFiClient();
}
void WiFiServer::begin(){
void WiFiServer::begin(uint16_t port){
if(_listening)
return;
if(port){
_port = port;
}
struct sockaddr_in server;
sockfd = socket(AF_INET , SOCK_STREAM, 0);
if (sockfd < 0)

View File

@ -39,7 +39,7 @@ class WiFiServer : public Server {
~WiFiServer(){ end();}
WiFiClient available();
WiFiClient accept(){return available();}
void begin();
void begin(uint16_t port=0);
void setNoDelay(bool nodelay);
bool getNoDelay();
bool hasClient();

View File

@ -17,6 +17,7 @@
#include <algorithm>
#include <string>
#include "ssl_client.h"
#include "WiFi.h"
const char *pers = "esp32-tls";
@ -60,14 +61,11 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p
return ssl_client->socket;
}
struct hostent *server;
server = gethostbyname(host);
if (server == NULL) {
log_e("gethostbyname failed");
IPAddress srv((uint32_t)0);
if(!WiFiGenericClass::hostByName(host, srv)){
return -1;
}
IPAddress srv((const uint8_t *)(server->h_addr));
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;

View File

@ -19,7 +19,8 @@
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
*/
Modified Nov 2017 by Chuck Todd (ctodd@cableone.net) - ESP32 ISR Support
*/
extern "C" {
#include <stdlib.h>
@ -38,64 +39,80 @@ TwoWire::TwoWire(uint8_t bus_num)
,i2c(NULL)
,rxIndex(0)
,rxLength(0)
,rxQueued(0)
,txIndex(0)
,txLength(0)
,txAddress(0)
,txQueued(0)
,transmitting(0)
,last_error(I2C_ERROR_OK)
,_timeOutMillis(50)
{}
TwoWire::~TwoWire()
{
flush();
if(i2c) {
i2cRelease(i2c);
i2c=NULL;
}
}
void TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency)
{
if(sdaPin < 0) { // default param passed
if(num == 0) {
if(sda==-1) sdaPin = SDA; //use Default Pin
else sdaPin = sda; // reuse prior pin
if(sda==-1) {
sdaPin = SDA; //use Default Pin
} else {
sdaPin = sda; // reuse prior pin
}
} else {
if(sda==-1) {
log_e("no Default SDA Pin for Second Peripheral");
return; //no Default pin for Second Peripheral
} else sdaPin = sda; // reuse prior pin
} else {
sdaPin = sda; // reuse prior pin
}
}
}
if(sclPin < 0) { // default param passed
if(num == 0) {
if(scl==-1) sclPin = SCL; // use Default pin
else sclPin = scl; // reuse prior pin
if(scl == -1) {
sclPin = SCL; // use Default pin
} else {
sclPin = scl; // reuse prior pin
}
} else {
if(scl==-1){
if(scl == -1) {
log_e("no Default SCL Pin for Second Peripheral");
return; //no Default pin for Second Peripheral
} else sclPin = scl; // reuse prior pin
} else {
sclPin = scl; // reuse prior pin
}
}
}
if(i2c == NULL) {
i2c = i2cInit(num, 0, false);
if(i2c == NULL) {
return;
}
}
i2cSetFrequency(i2c, frequency);
if(sda >= 0 && sda != sdaPin) {
i2cDetachSDA(i2c, sda);
}
if(scl >= 0 && scl != sclPin) {
i2cDetachSCL(i2c, scl);
}
sda = sdaPin;
scl = sclPin;
i2cAttachSDA(i2c, sda);
i2cAttachSCL(i2c, scl);
i2c = i2cInit(num, sdaPin, sclPin, frequency);
if(!i2c) {
return;
}
flush();
i2cInitFix(i2c);
}
void TwoWire::setTimeOut(uint16_t timeOutMillis)
{
_timeOutMillis = timeOutMillis;
}
uint16_t TwoWire::getTimeOut()
{
return _timeOutMillis;
}
void TwoWire::setClock(uint32_t frequency)
@ -103,62 +120,82 @@ void TwoWire::setClock(uint32_t frequency)
i2cSetFrequency(i2c, frequency);
}
size_t TwoWire::requestFrom(uint8_t address, size_t size, bool sendStop)
size_t TwoWire::getClock()
{
if(size > I2C_BUFFER_LENGTH) {
size = I2C_BUFFER_LENGTH;
}
size_t read = (i2cRead(i2c, address, false, rxBuffer, size, sendStop) == 0)?size:0;
rxIndex = 0;
rxLength = read;
return read;
return i2cGetFrequency(i2c);
}
uint8_t TwoWire::endTransmission(uint8_t sendStop)
/* stickBreaker Nov 2017 ISR, and bigblock 64k-1
*/
i2c_err_t TwoWire::writeTransmission(uint16_t address, uint8_t *buff, uint16_t size, bool sendStop)
{
int8_t ret = i2cWrite(i2c, txAddress, false, txBuffer, txLength, sendStop);
txIndex = 0;
txLength = 0;
transmitting = 0;
return ret;
last_error = i2cWrite(i2c, address, buff, size, sendStop, _timeOutMillis);
return last_error;
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
i2c_err_t TwoWire::readTransmission(uint16_t address, uint8_t *buff, uint16_t size, bool sendStop, uint32_t *readCount)
{
return requestFrom(address, static_cast<size_t>(quantity), static_cast<bool>(sendStop));
last_error = i2cRead(i2c, address, buff, size, sendStop, _timeOutMillis, readCount);
return last_error;
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
{
return requestFrom(address, static_cast<size_t>(quantity), true);
}
uint8_t TwoWire::requestFrom(int address, int quantity)
{
return requestFrom(static_cast<uint8_t>(address), static_cast<size_t>(quantity), true);
}
uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop)
{
return requestFrom(static_cast<uint8_t>(address), static_cast<size_t>(quantity), static_cast<bool>(sendStop));
}
void TwoWire::beginTransmission(uint8_t address)
void TwoWire::beginTransmission(uint16_t address)
{
transmitting = 1;
txAddress = address;
txIndex = txQueued; // allow multiple beginTransmission(),write(),endTransmission(false) until endTransmission(true)
txLength = txQueued;
}
/*stickbreaker isr
*/
uint8_t TwoWire::endTransmission(bool sendStop) // Assumes Wire.beginTransaction(), Wire.write()
{
if(transmitting == 1) {
last_error = writeTransmission(txAddress, &txBuffer[txQueued], txLength - txQueued, sendStop);
rxIndex = 0;
rxLength = rxQueued;
rxQueued = 0;
txQueued = 0; // the SendStop=true will restart all Queueing
if(last_error == I2C_ERROR_CONTINUE){
// txlength is howmany bytes in txbuffer have been use
txQueued = txLength;
}
} else {
last_error = I2C_ERROR_NO_BEGIN;
flush();
}
txIndex = 0;
txLength = 0;
transmitting = 0;
return last_error;
}
void TwoWire::beginTransmission(int address)
/* @stickBreaker 11/2017 fix for ReSTART timeout, ISR
*/
uint8_t TwoWire::requestFrom(uint16_t address, uint8_t size, bool sendStop)
{
beginTransmission((uint8_t)address);
}
//use internal Wire rxBuffer, multiple requestFrom()'s may be pending, try to share rxBuffer
uint32_t cnt = rxQueued; // currently queued reads, next available position in rxBuffer
if(cnt < (I2C_BUFFER_LENGTH-1) && (size + cnt) <= I2C_BUFFER_LENGTH) { // any room left in rxBuffer
rxQueued += size;
} else { // no room to receive more!
log_e("rxBuff overflow %d", cnt + size);
cnt = 0;
last_error = I2C_ERROR_MEMORY;
flush();
return cnt;
}
uint8_t TwoWire::endTransmission(void)
{
return endTransmission(true);
last_error = readTransmission(address, &rxBuffer[cnt], size, sendStop, &cnt);
rxIndex = 0;
rxLength = rxQueued;
rxQueued = 0;
txQueued = 0; // the SendStop=true will restart all Queueing
if(last_error != I2C_ERROR_OK){
cnt = 0;
}
return cnt;
}
size_t TwoWire::write(uint8_t data)
@ -170,8 +207,9 @@ size_t TwoWire::write(uint8_t data)
txBuffer[txIndex] = data;
++txIndex;
txLength = txIndex;
return 1;
}
return 1;
return 0;
}
size_t TwoWire::write(const uint8_t *data, size_t quantity)
@ -182,8 +220,9 @@ size_t TwoWire::write(const uint8_t *data, size_t quantity)
return i;
}
}
return quantity;
}
return quantity;
return 0;
}
int TwoWire::available(void)
@ -217,13 +256,111 @@ void TwoWire::flush(void)
rxLength = 0;
txIndex = 0;
txLength = 0;
rxQueued = 0;
txQueued = 0;
i2cFlush(i2c); // cleanup
}
void TwoWire::reset(void)
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
{
i2cReset( i2c );
i2c = NULL;
begin( sda, scl );
return requestFrom(static_cast<uint16_t>(address), static_cast<size_t>(quantity), static_cast<bool>(sendStop));
}
uint8_t TwoWire::requestFrom(uint16_t address, uint8_t quantity, uint8_t sendStop)
{
return requestFrom(address, static_cast<size_t>(quantity), static_cast<bool>(sendStop));
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
{
return requestFrom(static_cast<uint16_t>(address), static_cast<size_t>(quantity), true);
}
uint8_t TwoWire::requestFrom(uint16_t address, uint8_t quantity)
{
return requestFrom(address, static_cast<size_t>(quantity), true);
}
uint8_t TwoWire::requestFrom(int address, int quantity)
{
return requestFrom(static_cast<uint16_t>(address), static_cast<size_t>(quantity), true);
}
uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop)
{
return static_cast<uint8_t>(requestFrom(static_cast<uint16_t>(address), static_cast<size_t>(quantity), static_cast<bool>(sendStop)));
}
void TwoWire::beginTransmission(int address)
{
beginTransmission(static_cast<uint16_t>(address));
}
void TwoWire::beginTransmission(uint8_t address)
{
beginTransmission(static_cast<uint16_t>(address));
}
uint8_t TwoWire::endTransmission(void)
{
return endTransmission(true);
}
uint8_t TwoWire::endTransmission(uint8_t sendStop)
{
return endTransmission(static_cast<bool>(sendStop));
}
/* stickbreaker Nov2017 better error reporting
*/
uint8_t TwoWire::lastError()
{
return (uint8_t)last_error;
}
const char ERRORTEXT[] =
"OK\0"
"DEVICE\0"
"ACK\0"
"TIMEOUT\0"
"BUS\0"
"BUSY\0"
"MEMORY\0"
"CONTINUE\0"
"NO_BEGIN\0"
"\0";
char * TwoWire::getErrorText(uint8_t err)
{
uint8_t t = 0;
bool found = false;
char * message = (char*)&ERRORTEXT;
while(!found && message[0]) {
found = t == err;
if(!found) {
message = message + strlen(message) + 1;
t++;
}
}
if(!found) {
return NULL;
} else {
return message;
}
}
/*stickbreaker Dump i2c Interrupt buffer, i2c isr Debugging
*/
void TwoWire::dumpInts()
{
i2cDumpInts(num);
}
void TwoWire::dumpI2C()
{
i2cDumpI2c(i2c);
}
TwoWire Wire = TwoWire(0);

View File

@ -19,6 +19,7 @@
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
Modified November 2017 by Chuck Todd <stickbreaker on GitHub> to use ISR and increase stability.
*/
#ifndef TwoWire_h
@ -29,7 +30,10 @@
#include "freertos/queue.h"
#include "Stream.h"
#define STICKBREAKER V0.2.2
#define I2C_BUFFER_LENGTH 128
typedef void(*user_onRequest)(void);
typedef void(*user_onReceive)(uint8_t*, int);
class TwoWire: public Stream
{
@ -42,28 +46,57 @@ protected:
uint8_t rxBuffer[I2C_BUFFER_LENGTH];
uint16_t rxIndex;
uint16_t rxLength;
uint16_t rxQueued; //@stickBreaker
uint8_t txBuffer[I2C_BUFFER_LENGTH];
uint16_t txIndex;
uint16_t txLength;
uint8_t txAddress;
uint16_t txAddress;
uint16_t txQueued; //@stickbreaker
uint8_t transmitting;
/* slave Mode, not yet Stickbreaker
static user_onRequest uReq[2];
static user_onReceive uRcv[2];
void onRequestService(void);
void onReceiveService(uint8_t*, int);
*/
i2c_err_t last_error; // @stickBreaker from esp32-hal-i2c.h
uint16_t _timeOutMillis;
public:
TwoWire(uint8_t bus_num);
void begin(int sda=-1, int scl=-1, uint32_t frequency=100000);
void setClock(uint32_t);
void beginTransmission(uint8_t);
void beginTransmission(int);
uint8_t endTransmission(void);
uint8_t endTransmission(uint8_t);
size_t requestFrom(uint8_t address, size_t size, bool sendStop);
~TwoWire();
void begin(int sda=-1, int scl=-1, uint32_t frequency=0);
uint8_t requestFrom(uint8_t, uint8_t);
uint8_t requestFrom(uint8_t, uint8_t, uint8_t);
uint8_t requestFrom(int, int);
uint8_t requestFrom(int, int, int);
void setClock(uint32_t frequency); // change bus clock without initing hardware
size_t getClock(); // current bus clock rate in hz
void setTimeOut(uint16_t timeOutMillis);
uint16_t getTimeOut();
uint8_t lastError();
char * getErrorText(uint8_t err);
//@stickBreaker for big blocks and ISR model
i2c_err_t writeTransmission(uint16_t address, uint8_t* buff, uint16_t size, bool sendStop=true);
i2c_err_t readTransmission(uint16_t address, uint8_t* buff, uint16_t size, bool sendStop=true, uint32_t *readCount=NULL);
void beginTransmission(uint16_t address);
void beginTransmission(uint8_t address);
void beginTransmission(int address);
uint8_t endTransmission(bool sendStop);
uint8_t endTransmission(uint8_t sendStop);
uint8_t endTransmission(void);
uint8_t requestFrom(uint16_t address, uint8_t size, bool sendStop);
uint8_t requestFrom(uint16_t address, uint8_t size, uint8_t sendStop);
uint8_t requestFrom(uint16_t address, uint8_t size);
uint8_t requestFrom(uint8_t address, uint8_t size, uint8_t sendStop);
uint8_t requestFrom(uint8_t address, uint8_t size);
uint8_t requestFrom(int address, int size, int sendStop);
uint8_t requestFrom(int address, int size);
size_t write(uint8_t);
size_t write(const uint8_t *, size_t);
@ -72,8 +105,6 @@ public:
int peek(void);
void flush(void);
void reset(void);
inline size_t write(const char * s)
{
return write((uint8_t*) s, strlen(s));
@ -94,8 +125,19 @@ public:
{
return write((uint8_t)n);
}
void onReceive( void (*)(int) );
void onRequest( void (*)(void) );
void dumpInts();
void dumpI2C();
};
extern TwoWire Wire;
/*
V0.2.2 13APR2018 preserve custom SCL,SDA,Frequency when no parameters passed to begin()
V0.2.1 15MAR2018 Hardware reset, Glitch prevention, adding destructor for second i2c testing
*/
#endif