1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

Migrate from astyle to clang-format (#8464)

This commit is contained in:
Maxim Prokhorov 2022-02-20 19:23:33 +03:00 committed by Max Prokhorov
parent 46190b61f1
commit 19b7a29720
241 changed files with 15925 additions and 16197 deletions

View File

@ -238,11 +238,20 @@ jobs:
python-version: '3.x' python-version: '3.x'
- name: Style check - name: Style check
env: env:
LLVM_SNAPSHOT_KEY: "6084F3CF814B57C1CF12EFD515CF4D18AF4F7421"
TRAVIS_BUILD_DIR: ${{ github.workspace }} TRAVIS_BUILD_DIR: ${{ github.workspace }}
TRAVIS_TAG: ${{ github.ref }} TRAVIS_TAG: ${{ github.ref }}
run: | run: |
export GNUPGHOME=$(mktemp -d)
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$LLVM_SNAPSHOT_KEY"
gpg --batch --armor --export "$LLVM_SNAPSHOT_KEY" | \
sudo tee /etc/apt/trusted.gpg.d/llvm-snapshot.gpg.asc
rm -r $GNUPGHOME
echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main" | \
sudo tee /etc/apt/sources.list.d/llvm.list
sudo apt update sudo apt update
sudo apt install astyle sudo apt install clang-format-13
pip3 install pyyaml
bash ./tests/ci/style_check.sh bash ./tests/ci/style_check.sh

View File

@ -23,7 +23,7 @@
// these functions must exists as-is with "C" interface, // these functions must exists as-is with "C" interface,
// nonos-sdk calls them at boot time and later // nonos-sdk calls them at boot time and later
#include <lwip/init.h> // LWIP_VERSION #include <lwip/init.h> // LWIP_VERSION
#include <lwip/netif.h> #include <lwip/netif.h>
#include "LwipDhcpServer.h" #include "LwipDhcpServer.h"
@ -35,8 +35,7 @@ DhcpServer dhcpSoftAP(&netif_git[SOFTAP_IF]);
extern "C" extern "C"
{ {
void dhcps_start(struct ip_info* info, netif* apnetif)
void dhcps_start(struct ip_info *info, netif* apnetif)
{ {
// apnetif is esp interface, replaced by lwip2's // apnetif is esp interface, replaced by lwip2's
// netif_git[SOFTAP_IF] interface in constructor // netif_git[SOFTAP_IF] interface in constructor
@ -61,4 +60,4 @@ extern "C"
dhcpSoftAP.end(); dhcpSoftAP.end();
} }
} // extern "C" } // extern "C"

File diff suppressed because it is too large Load Diff

View File

@ -31,12 +31,11 @@
#ifndef __DHCPS_H__ #ifndef __DHCPS_H__
#define __DHCPS_H__ #define __DHCPS_H__
#include <lwip/init.h> // LWIP_VERSION #include <lwip/init.h> // LWIP_VERSION
class DhcpServer class DhcpServer
{ {
public: public:
DhcpServer(netif* netif); DhcpServer(netif* netif);
~DhcpServer(); ~DhcpServer();
@ -53,72 +52,64 @@ public:
// legacy public C structure and API to eventually turn into C++ // legacy public C structure and API to eventually turn into C++
void init_dhcps_lease(uint32 ip); void init_dhcps_lease(uint32 ip);
bool set_dhcps_lease(struct dhcps_lease *please); bool set_dhcps_lease(struct dhcps_lease* please);
bool get_dhcps_lease(struct dhcps_lease *please); bool get_dhcps_lease(struct dhcps_lease* please);
bool set_dhcps_offer_option(uint8 level, void* optarg); bool set_dhcps_offer_option(uint8 level, void* optarg);
bool set_dhcps_lease_time(uint32 minute); bool set_dhcps_lease_time(uint32 minute);
bool reset_dhcps_lease_time(void); bool reset_dhcps_lease_time(void);
uint32 get_dhcps_lease_time(void); uint32 get_dhcps_lease_time(void);
bool add_dhcps_lease(uint8 *macaddr); bool add_dhcps_lease(uint8* macaddr);
void dhcps_set_dns(int num, const ipv4_addr_t* dns); void dhcps_set_dns(int num, const ipv4_addr_t* dns);
protected: protected:
// legacy C structure and API to eventually turn into C++ // legacy C structure and API to eventually turn into C++
typedef struct _list_node typedef struct _list_node
{ {
void *pnode; void* pnode;
struct _list_node *pnext; struct _list_node* pnext;
} list_node; } list_node;
void node_insert_to_list(list_node **phead, list_node* pinsert); void node_insert_to_list(list_node** phead, list_node* pinsert);
void node_remove_from_list(list_node **phead, list_node* pdelete); void node_remove_from_list(list_node** phead, list_node* pdelete);
uint8_t* add_msg_type(uint8_t *optptr, uint8_t type); uint8_t* add_msg_type(uint8_t* optptr, uint8_t type);
uint8_t* add_offer_options(uint8_t *optptr); uint8_t* add_offer_options(uint8_t* optptr);
uint8_t* add_end(uint8_t *optptr); uint8_t* add_end(uint8_t* optptr);
void create_msg(struct dhcps_msg *m); void create_msg(struct dhcps_msg* m);
void send_offer(struct dhcps_msg *m); void send_offer(struct dhcps_msg* m);
void send_nak(struct dhcps_msg *m); void send_nak(struct dhcps_msg* m);
void send_ack(struct dhcps_msg *m); void send_ack(struct dhcps_msg* m);
uint8_t parse_options(uint8_t *optptr, sint16_t len); uint8_t parse_options(uint8_t* optptr, sint16_t len);
sint16_t parse_msg(struct dhcps_msg *m, u16_t len); sint16_t parse_msg(struct dhcps_msg* m, u16_t len);
static void S_handle_dhcp(void *arg, static void S_handle_dhcp(void* arg, struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* addr,
struct udp_pcb *pcb,
struct pbuf *p,
const ip_addr_t *addr,
uint16_t port); uint16_t port);
void handle_dhcp( void handle_dhcp(struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* addr, uint16_t port);
struct udp_pcb *pcb, void kill_oldest_dhcps_pool(void);
struct pbuf *p, void dhcps_coarse_tmr(void); // CURRENTLY NOT CALLED
const ip_addr_t *addr, void dhcps_client_leave(u8* bssid, struct ipv4_addr* ip, bool force);
uint16_t port); uint32 dhcps_client_update(u8* bssid, struct ipv4_addr* ip);
void kill_oldest_dhcps_pool(void);
void dhcps_coarse_tmr(void); // CURRENTLY NOT CALLED
void dhcps_client_leave(u8 *bssid, struct ipv4_addr *ip, bool force);
uint32 dhcps_client_update(u8 *bssid, struct ipv4_addr *ip);
netif* _netif; netif* _netif;
struct udp_pcb *pcb_dhcps; struct udp_pcb* pcb_dhcps;
ip_addr_t broadcast_dhcps; ip_addr_t broadcast_dhcps;
struct ipv4_addr server_address; struct ipv4_addr server_address;
struct ipv4_addr client_address; struct ipv4_addr client_address;
struct ipv4_addr dns_address; struct ipv4_addr dns_address;
uint32 dhcps_lease_time; uint32 dhcps_lease_time;
struct dhcps_lease dhcps_lease; struct dhcps_lease dhcps_lease;
list_node *plist; list_node* plist;
uint8 offer; uint8 offer;
bool renew; bool renew;
static const uint32 magic_cookie; static const uint32 magic_cookie;
}; };
// SoftAP DHCP server always exists and is started on boot // SoftAP DHCP server always exists and is started on boot
extern DhcpServer dhcpSoftAP; extern DhcpServer dhcpSoftAP;
extern "C" int fw_has_started_softap_dhcps; extern "C" int fw_has_started_softap_dhcps;
#endif // __DHCPS_H__ #endif // __DHCPS_H__

View File

@ -1,12 +1,13 @@
extern "C" { extern "C"
{
#include "lwip/err.h" #include "lwip/err.h"
#include "lwip/ip_addr.h" #include "lwip/ip_addr.h"
#include "lwip/dns.h" #include "lwip/dns.h"
#include "lwip/dhcp.h" #include "lwip/dhcp.h"
#include "lwip/init.h" // LWIP_VERSION_ #include "lwip/init.h" // LWIP_VERSION_
#if LWIP_IPV6 #if LWIP_IPV6
#include "lwip/netif.h" // struct netif #include "lwip/netif.h" // struct netif
#endif #endif
#include <user_interface.h> #include <user_interface.h>
@ -24,19 +25,23 @@ extern "C" {
// //
// result stored into gateway/netmask/dns1 // result stored into gateway/netmask/dns1
bool LwipIntf::ipAddressReorder(const IPAddress& local_ip, const IPAddress& arg1, const IPAddress& arg2, const IPAddress& arg3, bool LwipIntf::ipAddressReorder(const IPAddress& local_ip, const IPAddress& arg1,
IPAddress& gateway, IPAddress& netmask, IPAddress& dns1) const IPAddress& arg2, const IPAddress& arg3, IPAddress& gateway,
IPAddress& netmask, IPAddress& dns1)
{ {
//To allow compatibility, check first octet of 3rd arg. If 255, interpret as ESP order, otherwise Arduino order. // To allow compatibility, check first octet of 3rd arg. If 255, interpret as ESP order,
// otherwise Arduino order.
gateway = arg1; gateway = arg1;
netmask = arg2; netmask = arg2;
dns1 = arg3; dns1 = arg3;
if (netmask[0] != 255) if (netmask[0] != 255)
{ {
//octet is not 255 => interpret as Arduino order // octet is not 255 => interpret as Arduino order
gateway = arg2; gateway = arg2;
netmask = arg3[0] == 0 ? IPAddress(255, 255, 255, 0) : arg3; //arg order is arduino and 4th arg not given => assign it arduino default netmask = arg3[0] == 0 ? IPAddress(255, 255, 255, 0)
: arg3; // arg order is arduino and 4th arg not given => assign it
// arduino default
dns1 = arg1; dns1 = arg1;
} }
@ -46,7 +51,7 @@ bool LwipIntf::ipAddressReorder(const IPAddress& local_ip, const IPAddress& arg1
return false; return false;
} }
//ip and gateway must be in the same netmask // ip and gateway must be in the same netmask
if (gateway.isSet() && (local_ip.v4() & netmask.v4()) != (gateway.v4() & netmask.v4())) if (gateway.isSet() && (local_ip.v4() & netmask.v4()) != (gateway.v4() & netmask.v4()))
{ {
return false; return false;
@ -143,7 +148,6 @@ bool LwipIntf::hostname(const char* aHostname)
// harmless for AP, also compatible with ethernet adapters (to come) // harmless for AP, also compatible with ethernet adapters (to come)
for (netif* intf = netif_list; intf; intf = intf->next) for (netif* intf = netif_list; intf; intf = intf->next)
{ {
// unconditionally update all known interfaces // unconditionally update all known interfaces
intf->hostname = wifi_station_get_hostname(); intf->hostname = wifi_station_get_hostname();
@ -162,4 +166,3 @@ bool LwipIntf::hostname(const char* aHostname)
return ret && compliant; return ret && compliant;
} }

View File

@ -10,8 +10,7 @@
class LwipIntf class LwipIntf
{ {
public: public:
using CBType = std::function<void(netif*)>;
using CBType = std::function <void(netif*)>;
static bool stateUpCB(LwipIntf::CBType&& cb); static bool stateUpCB(LwipIntf::CBType&& cb);
@ -24,12 +23,12 @@ public:
// arg3 | dns1 netmask // arg3 | dns1 netmask
// //
// result stored into gateway/netmask/dns1 // result stored into gateway/netmask/dns1
static static bool ipAddressReorder(const IPAddress& local_ip, const IPAddress& arg1,
bool ipAddressReorder(const IPAddress& local_ip, const IPAddress& arg1, const IPAddress& arg2, const IPAddress& arg3, const IPAddress& arg2, const IPAddress& arg3, IPAddress& gateway,
IPAddress& gateway, IPAddress& netmask, IPAddress& dns1); IPAddress& netmask, IPAddress& dns1);
String hostname(); String hostname();
bool hostname(const String& aHostname) bool hostname(const String& aHostname)
{ {
return hostname(aHostname.c_str()); return hostname(aHostname.c_str());
} }
@ -42,8 +41,7 @@ public:
const char* getHostname(); const char* getHostname();
protected: protected:
static bool stateChangeSysCB(LwipIntf::CBType&& cb); static bool stateChangeSysCB(LwipIntf::CBType&& cb);
}; };
#endif // _LWIPINTF_H #endif // _LWIPINTF_H

View File

@ -5,8 +5,8 @@
#define NETIF_STATUS_CB_SIZE 3 #define NETIF_STATUS_CB_SIZE 3
static int netifStatusChangeListLength = 0; static int netifStatusChangeListLength = 0;
LwipIntf::CBType netifStatusChangeList [NETIF_STATUS_CB_SIZE]; LwipIntf::CBType netifStatusChangeList[NETIF_STATUS_CB_SIZE];
extern "C" void netif_status_changed(struct netif* netif) extern "C" void netif_status_changed(struct netif* netif)
{ {
@ -33,12 +33,14 @@ bool LwipIntf::stateChangeSysCB(LwipIntf::CBType&& cb)
bool LwipIntf::stateUpCB(LwipIntf::CBType&& cb) bool LwipIntf::stateUpCB(LwipIntf::CBType&& cb)
{ {
return stateChangeSysCB([cb](netif * nif) return stateChangeSysCB(
{ [cb](netif* nif)
if (netif_is_up(nif))
schedule_function([cb, nif]()
{ {
cb(nif); if (netif_is_up(nif))
schedule_function(
[cb, nif]()
{
cb(nif);
});
}); });
});
} }

View File

@ -14,7 +14,7 @@
#include <lwip/dns.h> #include <lwip/dns.h>
#include <lwip/apps/sntp.h> #include <lwip/apps/sntp.h>
#include <user_interface.h> // wifi_get_macaddr() #include <user_interface.h> // wifi_get_macaddr()
#include "SPI.h" #include "SPI.h"
#include "Schedule.h" #include "Schedule.h"
@ -25,41 +25,36 @@
#define DEFAULT_MTU 1500 #define DEFAULT_MTU 1500
#endif #endif
template <class RawDev> template<class RawDev>
class LwipIntfDev: public LwipIntf, public RawDev class LwipIntfDev: public LwipIntf, public RawDev
{ {
public: public:
LwipIntfDev(int8_t cs = SS, SPIClass& spi = SPI, int8_t intr = -1) :
LwipIntfDev(int8_t cs = SS, SPIClass& spi = SPI, int8_t intr = -1): RawDev(cs, spi, intr), _mtu(DEFAULT_MTU), _intrPin(intr), _started(false), _default(false)
RawDev(cs, spi, intr),
_mtu(DEFAULT_MTU),
_intrPin(intr),
_started(false),
_default(false)
{ {
memset(&_netif, 0, sizeof(_netif)); memset(&_netif, 0, sizeof(_netif));
} }
boolean config(const IPAddress& local_ip, const IPAddress& arg1, const IPAddress& arg2, const IPAddress& arg3 = IPADDR_NONE, const IPAddress& dns2 = IPADDR_NONE); boolean config(const IPAddress& local_ip, const IPAddress& arg1, const IPAddress& arg2,
const IPAddress& arg3 = IPADDR_NONE, const IPAddress& dns2 = IPADDR_NONE);
// default mac-address is inferred from esp8266's STA interface // default mac-address is inferred from esp8266's STA interface
boolean begin(const uint8_t *macAddress = nullptr, const uint16_t mtu = DEFAULT_MTU); boolean begin(const uint8_t* macAddress = nullptr, const uint16_t mtu = DEFAULT_MTU);
const netif* getNetIf() const const netif* getNetIf() const
{ {
return &_netif; return &_netif;
} }
IPAddress localIP() const IPAddress localIP() const
{ {
return IPAddress(ip4_addr_get_u32(ip_2_ip4(&_netif.ip_addr))); return IPAddress(ip4_addr_get_u32(ip_2_ip4(&_netif.ip_addr)));
} }
IPAddress subnetMask() const IPAddress subnetMask() const
{ {
return IPAddress(ip4_addr_get_u32(ip_2_ip4(&_netif.netmask))); return IPAddress(ip4_addr_get_u32(ip_2_ip4(&_netif.netmask)));
} }
IPAddress gatewayIP() const IPAddress gatewayIP() const
{ {
return IPAddress(ip4_addr_get_u32(ip_2_ip4(&_netif.gw))); return IPAddress(ip4_addr_get_u32(ip_2_ip4(&_netif.gw)));
} }
@ -77,12 +72,11 @@ public:
wl_status_t status(); wl_status_t status();
protected: protected:
err_t netif_init(); err_t netif_init();
void netif_status_callback(); void netif_status_callback();
static err_t netif_init_s(netif* netif); static err_t netif_init_s(netif* netif);
static err_t linkoutput_s(netif *netif, struct pbuf *p); static err_t linkoutput_s(netif* netif, struct pbuf* p);
static void netif_status_callback_s(netif* netif); static void netif_status_callback_s(netif* netif);
// called on a regular basis or on interrupt // called on a regular basis or on interrupt
@ -90,18 +84,19 @@ protected:
// members // members
netif _netif; netif _netif;
uint16_t _mtu;
int8_t _intrPin;
uint8_t _macAddress[6];
bool _started;
bool _default;
uint16_t _mtu;
int8_t _intrPin;
uint8_t _macAddress[6];
bool _started;
bool _default;
}; };
template <class RawDev> template<class RawDev>
boolean LwipIntfDev<RawDev>::config(const IPAddress& localIP, const IPAddress& gateway, const IPAddress& netmask, const IPAddress& dns1, const IPAddress& dns2) boolean LwipIntfDev<RawDev>::config(const IPAddress& localIP, const IPAddress& gateway,
const IPAddress& netmask, const IPAddress& dns1,
const IPAddress& dns2)
{ {
if (_started) if (_started)
{ {
@ -132,7 +127,7 @@ boolean LwipIntfDev<RawDev>::config(const IPAddress& localIP, const IPAddress& g
return true; return true;
} }
template <class RawDev> template<class RawDev>
boolean LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu) boolean LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu)
{ {
if (mtu) if (mtu)
@ -162,9 +157,9 @@ boolean LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu
memset(_macAddress, 0, 6); memset(_macAddress, 0, 6);
_macAddress[0] = 0xEE; _macAddress[0] = 0xEE;
#endif #endif
_macAddress[3] += _netif.num; // alter base mac address _macAddress[3] += _netif.num; // alter base mac address
_macAddress[0] &= 0xfe; // set as locally administered, unicast, per _macAddress[0] &= 0xfe; // set as locally administered, unicast, per
_macAddress[0] |= 0x02; // https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local _macAddress[0] |= 0x02; // https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local
} }
if (!RawDev::begin(_macAddress)) if (!RawDev::begin(_macAddress))
@ -183,7 +178,8 @@ boolean LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu
ip_addr_copy(netmask, _netif.netmask); ip_addr_copy(netmask, _netif.netmask);
ip_addr_copy(gw, _netif.gw); ip_addr_copy(gw, _netif.gw);
if (!netif_add(&_netif, ip_2_ip4(&ip_addr), ip_2_ip4(&netmask), ip_2_ip4(&gw), this, netif_init_s, ethernet_input)) if (!netif_add(&_netif, ip_2_ip4(&ip_addr), ip_2_ip4(&netmask), ip_2_ip4(&gw), this,
netif_init_s, ethernet_input))
{ {
return false; return false;
} }
@ -212,20 +208,24 @@ boolean LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu
{ {
if (RawDev::interruptIsPossible()) if (RawDev::interruptIsPossible())
{ {
//attachInterrupt(_intrPin, [&]() { this->handlePackets(); }, FALLING); // attachInterrupt(_intrPin, [&]() { this->handlePackets(); }, FALLING);
} }
else else
{ {
::printf((PGM_P)F("lwIP_Intf: Interrupt not implemented yet, enabling transparent polling\r\n")); ::printf((PGM_P)F(
"lwIP_Intf: Interrupt not implemented yet, enabling transparent polling\r\n"));
_intrPin = -1; _intrPin = -1;
} }
} }
if (_intrPin < 0 && !schedule_recurrent_function_us([&]() if (_intrPin < 0
{ && !schedule_recurrent_function_us(
this->handlePackets(); [&]()
return true; {
}, 100)) this->handlePackets();
return true;
},
100))
{ {
netif_remove(&_netif); netif_remove(&_netif);
return false; return false;
@ -234,14 +234,14 @@ boolean LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu
return true; return true;
} }
template <class RawDev> template<class RawDev>
wl_status_t LwipIntfDev<RawDev>::status() wl_status_t LwipIntfDev<RawDev>::status()
{ {
return _started ? (connected() ? WL_CONNECTED : WL_DISCONNECTED) : WL_NO_SHIELD; return _started ? (connected() ? WL_CONNECTED : WL_DISCONNECTED) : WL_NO_SHIELD;
} }
template <class RawDev> template<class RawDev>
err_t LwipIntfDev<RawDev>::linkoutput_s(netif *netif, struct pbuf *pbuf) err_t LwipIntfDev<RawDev>::linkoutput_s(netif* netif, struct pbuf* pbuf)
{ {
LwipIntfDev* ths = (LwipIntfDev*)netif->state; LwipIntfDev* ths = (LwipIntfDev*)netif->state;
@ -255,37 +255,34 @@ err_t LwipIntfDev<RawDev>::linkoutput_s(netif *netif, struct pbuf *pbuf)
#if PHY_HAS_CAPTURE #if PHY_HAS_CAPTURE
if (phy_capture) if (phy_capture)
{ {
phy_capture(ths->_netif.num, (const char*)pbuf->payload, pbuf->len, /*out*/1, /*success*/len == pbuf->len); phy_capture(ths->_netif.num, (const char*)pbuf->payload, pbuf->len, /*out*/ 1,
/*success*/ len == pbuf->len);
} }
#endif #endif
return len == pbuf->len ? ERR_OK : ERR_MEM; return len == pbuf->len ? ERR_OK : ERR_MEM;
} }
template <class RawDev> template<class RawDev>
err_t LwipIntfDev<RawDev>::netif_init_s(struct netif* netif) err_t LwipIntfDev<RawDev>::netif_init_s(struct netif* netif)
{ {
return ((LwipIntfDev*)netif->state)->netif_init(); return ((LwipIntfDev*)netif->state)->netif_init();
} }
template <class RawDev> template<class RawDev>
void LwipIntfDev<RawDev>::netif_status_callback_s(struct netif* netif) void LwipIntfDev<RawDev>::netif_status_callback_s(struct netif* netif)
{ {
((LwipIntfDev*)netif->state)->netif_status_callback(); ((LwipIntfDev*)netif->state)->netif_status_callback();
} }
template <class RawDev> template<class RawDev>
err_t LwipIntfDev<RawDev>::netif_init() err_t LwipIntfDev<RawDev>::netif_init()
{ {
_netif.name[0] = 'e'; _netif.name[0] = 'e';
_netif.name[1] = '0' + _netif.num; _netif.name[1] = '0' + _netif.num;
_netif.mtu = _mtu; _netif.mtu = _mtu;
_netif.chksum_flags = NETIF_CHECKSUM_ENABLE_ALL; _netif.chksum_flags = NETIF_CHECKSUM_ENABLE_ALL;
_netif.flags = _netif.flags = NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP | NETIF_FLAG_BROADCAST | NETIF_FLAG_LINK_UP;
NETIF_FLAG_ETHARP
| NETIF_FLAG_IGMP
| NETIF_FLAG_BROADCAST
| NETIF_FLAG_LINK_UP;
// lwIP's doc: This function typically first resolves the hardware // lwIP's doc: This function typically first resolves the hardware
// address, then sends the packet. For ethernet physical layer, this is // address, then sends the packet. For ethernet physical layer, this is
@ -301,7 +298,7 @@ err_t LwipIntfDev<RawDev>::netif_init()
return ERR_OK; return ERR_OK;
} }
template <class RawDev> template<class RawDev>
void LwipIntfDev<RawDev>::netif_status_callback() void LwipIntfDev<RawDev>::netif_status_callback()
{ {
if (connected()) if (connected())
@ -321,14 +318,14 @@ void LwipIntfDev<RawDev>::netif_status_callback()
} }
} }
template <class RawDev> template<class RawDev>
err_t LwipIntfDev<RawDev>::handlePackets() err_t LwipIntfDev<RawDev>::handlePackets()
{ {
int pkt = 0; int pkt = 0;
while (1) while (1)
{ {
if (++pkt == 10) if (++pkt == 10)
// prevent starvation // prevent starvation
{ {
return ERR_OK; return ERR_OK;
} }
@ -374,7 +371,8 @@ err_t LwipIntfDev<RawDev>::handlePackets()
#if PHY_HAS_CAPTURE #if PHY_HAS_CAPTURE
if (phy_capture) if (phy_capture)
{ {
phy_capture(_netif.num, (const char*)pbuf->payload, tot_len, /*out*/0, /*success*/err == ERR_OK); phy_capture(_netif.num, (const char*)pbuf->payload, tot_len, /*out*/ 0,
/*success*/ err == ERR_OK);
} }
#endif #endif
@ -384,11 +382,10 @@ err_t LwipIntfDev<RawDev>::handlePackets()
return err; return err;
} }
// (else) allocated pbuf is now lwIP's responsibility // (else) allocated pbuf is now lwIP's responsibility
} }
} }
template <class RawDev> template<class RawDev>
void LwipIntfDev<RawDev>::setDefault() void LwipIntfDev<RawDev>::setDefault()
{ {
_default = true; _default = true;
@ -398,4 +395,4 @@ void LwipIntfDev<RawDev>::setDefault()
} }
} }
#endif // _LWIPINTFDEV_H #endif // _LWIPINTFDEV_H

View File

@ -19,20 +19,17 @@
parsing functions based on TextFinder library by Michael Margolis parsing functions based on TextFinder library by Michael Margolis
*/ */
#include <Arduino.h> #include <Arduino.h>
#include <StreamDev.h> #include <StreamDev.h>
size_t Stream::sendGeneric(Print* to, size_t Stream::sendGeneric(Print* to, const ssize_t len, const int readUntilChar,
const ssize_t len,
const int readUntilChar,
const esp8266::polledTimeout::oneShotFastMs::timeType timeoutMs) const esp8266::polledTimeout::oneShotFastMs::timeType timeoutMs)
{ {
setReport(Report::Success); setReport(Report::Success);
if (len == 0) if (len == 0)
{ {
return 0; // conveniently avoids timeout for no requested data return 0; // conveniently avoids timeout for no requested data
} }
// There are two timeouts: // There are two timeouts:
@ -57,14 +54,17 @@ size_t Stream::sendGeneric(Print* to,
return SendGenericRegular(to, len, timeoutMs); return SendGenericRegular(to, len, timeoutMs);
} }
size_t
size_t Stream::SendGenericPeekBuffer(Print* to, const ssize_t len, const int readUntilChar, const esp8266::polledTimeout::oneShotFastMs::timeType timeoutMs) Stream::SendGenericPeekBuffer(Print* to, const ssize_t len, const int readUntilChar,
const esp8266::polledTimeout::oneShotFastMs::timeType timeoutMs)
{ {
// "neverExpires (default, impossible)" is translated to default timeout // "neverExpires (default, impossible)" is translated to default timeout
esp8266::polledTimeout::oneShotFastMs timedOut(timeoutMs >= esp8266::polledTimeout::oneShotFastMs::neverExpires ? getTimeout() : timeoutMs); esp8266::polledTimeout::oneShotFastMs timedOut(
timeoutMs >= esp8266::polledTimeout::oneShotFastMs::neverExpires ? getTimeout()
: timeoutMs);
// len==-1 => maxLen=0 <=> until starvation // len==-1 => maxLen=0 <=> until starvation
const size_t maxLen = std::max((ssize_t)0, len); const size_t maxLen = std::max((ssize_t)0, len);
size_t written = 0; size_t written = 0;
while (!maxLen || written < maxLen) while (!maxLen || written < maxLen)
{ {
@ -90,13 +90,13 @@ size_t Stream::SendGenericPeekBuffer(Print* to, const ssize_t len, const int rea
if (w) if (w)
{ {
const char* directbuf = peekBuffer(); const char* directbuf = peekBuffer();
bool foundChar = false; bool foundChar = false;
if (readUntilChar >= 0) if (readUntilChar >= 0)
{ {
const char* last = (const char*)memchr(directbuf, readUntilChar, w); const char* last = (const char*)memchr(directbuf, readUntilChar, w);
if (last) if (last)
{ {
w = std::min((size_t)(last - directbuf), w); w = std::min((size_t)(last - directbuf), w);
foundChar = true; foundChar = true;
} }
} }
@ -104,7 +104,7 @@ size_t Stream::SendGenericPeekBuffer(Print* to, const ssize_t len, const int rea
{ {
peekConsume(w); peekConsume(w);
written += w; written += w;
timedOut.reset(); // something has been written timedOut.reset(); // something has been written
} }
if (foundChar) if (foundChar)
{ {
@ -145,16 +145,20 @@ size_t Stream::SendGenericPeekBuffer(Print* to, const ssize_t len, const int rea
return written; return written;
} }
size_t Stream::SendGenericRegularUntil(Print* to, const ssize_t len, const int readUntilChar, const esp8266::polledTimeout::oneShotFastMs::timeType timeoutMs) size_t
Stream::SendGenericRegularUntil(Print* to, const ssize_t len, const int readUntilChar,
const esp8266::polledTimeout::oneShotFastMs::timeType timeoutMs)
{ {
// regular Stream API // regular Stream API
// no other choice than reading byte by byte // no other choice than reading byte by byte
// "neverExpires (default, impossible)" is translated to default timeout // "neverExpires (default, impossible)" is translated to default timeout
esp8266::polledTimeout::oneShotFastMs timedOut(timeoutMs >= esp8266::polledTimeout::oneShotFastMs::neverExpires ? getTimeout() : timeoutMs); esp8266::polledTimeout::oneShotFastMs timedOut(
timeoutMs >= esp8266::polledTimeout::oneShotFastMs::neverExpires ? getTimeout()
: timeoutMs);
// len==-1 => maxLen=0 <=> until starvation // len==-1 => maxLen=0 <=> until starvation
const size_t maxLen = std::max((ssize_t)0, len); const size_t maxLen = std::max((ssize_t)0, len);
size_t written = 0; size_t written = 0;
while (!maxLen || written < maxLen) while (!maxLen || written < maxLen)
{ {
@ -186,7 +190,7 @@ size_t Stream::SendGenericRegularUntil(Print* to, const ssize_t len, const int r
break; break;
} }
written += 1; written += 1;
timedOut.reset(); // something has been written timedOut.reset(); // something has been written
} }
if (timedOut) if (timedOut)
@ -221,16 +225,19 @@ size_t Stream::SendGenericRegularUntil(Print* to, const ssize_t len, const int r
return written; return written;
} }
size_t Stream::SendGenericRegular(Print* to, const ssize_t len, const esp8266::polledTimeout::oneShotFastMs::timeType timeoutMs) size_t Stream::SendGenericRegular(Print* to, const ssize_t len,
const esp8266::polledTimeout::oneShotFastMs::timeType timeoutMs)
{ {
// regular Stream API // regular Stream API
// use an intermediary buffer // use an intermediary buffer
// "neverExpires (default, impossible)" is translated to default timeout // "neverExpires (default, impossible)" is translated to default timeout
esp8266::polledTimeout::oneShotFastMs timedOut(timeoutMs >= esp8266::polledTimeout::oneShotFastMs::neverExpires ? getTimeout() : timeoutMs); esp8266::polledTimeout::oneShotFastMs timedOut(
timeoutMs >= esp8266::polledTimeout::oneShotFastMs::neverExpires ? getTimeout()
: timeoutMs);
// len==-1 => maxLen=0 <=> until starvation // len==-1 => maxLen=0 <=> until starvation
const size_t maxLen = std::max((ssize_t)0, len); const size_t maxLen = std::max((ssize_t)0, len);
size_t written = 0; size_t written = 0;
while (!maxLen || written < maxLen) while (!maxLen || written < maxLen)
{ {
@ -243,7 +250,7 @@ size_t Stream::SendGenericRegular(Print* to, const ssize_t len, const esp8266::p
size_t w = to->availableForWrite(); size_t w = to->availableForWrite();
if (w == 0 && !to->outputCanTimeout()) if (w == 0 && !to->outputCanTimeout())
// no more data can be written, ever // no more data can be written, ever
{ {
break; break;
} }
@ -256,7 +263,7 @@ size_t Stream::SendGenericRegular(Print* to, const ssize_t len, const esp8266::p
w = std::min(w, (decltype(w))temporaryStackBufferSize); w = std::min(w, (decltype(w))temporaryStackBufferSize);
if (w) if (w)
{ {
char temp[w]; char temp[w];
ssize_t r = read(temp, w); ssize_t r = read(temp, w);
if (r < 0) if (r < 0)
{ {
@ -270,7 +277,7 @@ size_t Stream::SendGenericRegular(Print* to, const ssize_t len, const esp8266::p
setReport(Report::WriteError); setReport(Report::WriteError);
break; break;
} }
timedOut.reset(); // something has been written timedOut.reset(); // something has been written
} }
if (timedOut) if (timedOut)
@ -305,19 +312,19 @@ size_t Stream::SendGenericRegular(Print* to, const ssize_t len, const esp8266::p
return written; return written;
} }
Stream& operator << (Stream& out, String& string) Stream& operator<<(Stream& out, String& string)
{ {
StreamConstPtr(string).sendAll(out); StreamConstPtr(string).sendAll(out);
return out; return out;
} }
Stream& operator << (Stream& out, StreamString& stream) Stream& operator<<(Stream& out, StreamString& stream)
{ {
stream.sendAll(out); stream.sendAll(out);
return out; return out;
} }
Stream& operator << (Stream& out, Stream& stream) Stream& operator<<(Stream& out, Stream& stream)
{ {
if (stream.streamRemaining() < 0) if (stream.streamRemaining() < 0)
{ {
@ -339,13 +346,13 @@ Stream& operator << (Stream& out, Stream& stream)
return out; return out;
} }
Stream& operator << (Stream& out, const char* text) Stream& operator<<(Stream& out, const char* text)
{ {
StreamConstPtr(text, strlen_P(text)).sendAll(out); StreamConstPtr(text, strlen_P(text)).sendAll(out);
return out; return out;
} }
Stream& operator << (Stream& out, const __FlashStringHelper* text) Stream& operator<<(Stream& out, const __FlashStringHelper* text)
{ {
StreamConstPtr(text).sendAll(out); StreamConstPtr(text).sendAll(out);
return out; return out;

View File

@ -35,16 +35,9 @@
class S2Stream: public Stream class S2Stream: public Stream
{ {
public: public:
S2Stream(String& string, int peekPointer = -1) : string(&string), peekPointer(peekPointer) { }
S2Stream(String& string, int peekPointer = -1): S2Stream(String* string, int peekPointer = -1) : string(string), peekPointer(peekPointer) { }
string(&string), peekPointer(peekPointer)
{
}
S2Stream(String* string, int peekPointer = -1):
string(string), peekPointer(peekPointer)
{
}
virtual int available() override virtual int available() override
{ {
@ -207,18 +200,15 @@ public:
} }
protected: protected:
String* string; String* string;
int peekPointer; // -1:String is consumed / >=0:resettable pointer int peekPointer; // -1:String is consumed / >=0:resettable pointer
}; };
// StreamString is a S2Stream holding the String // StreamString is a S2Stream holding the String
class StreamString: public String, public S2Stream class StreamString: public String, public S2Stream
{ {
protected: protected:
void resetpp() void resetpp()
{ {
if (peekPointer > 0) if (peekPointer > 0)
@ -228,55 +218,68 @@ protected:
} }
public: public:
StreamString(StreamString&& bro) : String(bro), S2Stream(this) { }
StreamString(StreamString&& bro): String(bro), S2Stream(this) { } StreamString(const StreamString& bro) : String(bro), S2Stream(this) { }
StreamString(const StreamString& bro): String(bro), S2Stream(this) { }
// duplicate String constructors and operator=: // duplicate String constructors and operator=:
StreamString(const char* text = nullptr): String(text), S2Stream(this) { } StreamString(const char* text = nullptr) : String(text), S2Stream(this) { }
StreamString(const String& string): String(string), S2Stream(this) { } StreamString(const String& string) : String(string), S2Stream(this) { }
StreamString(const __FlashStringHelper *str): String(str), S2Stream(this) { } StreamString(const __FlashStringHelper* str) : String(str), S2Stream(this) { }
StreamString(String&& string): String(string), S2Stream(this) { } StreamString(String&& string) : String(string), S2Stream(this) { }
explicit StreamString(char c): String(c), S2Stream(this) { } explicit StreamString(char c) : String(c), S2Stream(this) { }
explicit StreamString(unsigned char c, unsigned char base = 10): String(c, base), S2Stream(this) { } explicit StreamString(unsigned char c, unsigned char base = 10) :
explicit StreamString(int i, unsigned char base = 10): String(i, base), S2Stream(this) { } String(c, base), S2Stream(this)
explicit StreamString(unsigned int i, unsigned char base = 10): String(i, base), S2Stream(this) { } {
explicit StreamString(long l, unsigned char base = 10): String(l, base), S2Stream(this) { } }
explicit StreamString(unsigned long l, unsigned char base = 10): String(l, base), S2Stream(this) { } explicit StreamString(int i, unsigned char base = 10) : String(i, base), S2Stream(this) { }
explicit StreamString(float f, unsigned char decimalPlaces = 2): String(f, decimalPlaces), S2Stream(this) { } explicit StreamString(unsigned int i, unsigned char base = 10) : String(i, base), S2Stream(this)
explicit StreamString(double d, unsigned char decimalPlaces = 2): String(d, decimalPlaces), S2Stream(this) { } {
}
explicit StreamString(long l, unsigned char base = 10) : String(l, base), S2Stream(this) { }
explicit StreamString(unsigned long l, unsigned char base = 10) :
String(l, base), S2Stream(this)
{
}
explicit StreamString(float f, unsigned char decimalPlaces = 2) :
String(f, decimalPlaces), S2Stream(this)
{
}
explicit StreamString(double d, unsigned char decimalPlaces = 2) :
String(d, decimalPlaces), S2Stream(this)
{
}
StreamString& operator= (const StreamString& rhs) StreamString& operator=(const StreamString& rhs)
{ {
String::operator=(rhs); String::operator=(rhs);
resetpp(); resetpp();
return *this; return *this;
} }
StreamString& operator= (const String& rhs) StreamString& operator=(const String& rhs)
{ {
String::operator=(rhs); String::operator=(rhs);
resetpp(); resetpp();
return *this; return *this;
} }
StreamString& operator= (const char* cstr) StreamString& operator=(const char* cstr)
{ {
String::operator=(cstr); String::operator=(cstr);
resetpp(); resetpp();
return *this; return *this;
} }
StreamString& operator= (const __FlashStringHelper* str) StreamString& operator=(const __FlashStringHelper* str)
{ {
String::operator=(str); String::operator=(str);
resetpp(); resetpp();
return *this; return *this;
} }
StreamString& operator= (String&& rval) StreamString& operator=(String&& rval)
{ {
String::operator=(rval); String::operator=(rval);
resetpp(); resetpp();
@ -284,4 +287,4 @@ public:
} }
}; };
#endif // __STREAMSTRING_H #endif // __STREAMSTRING_H

View File

@ -24,9 +24,8 @@
#include "wiring_private.h" #include "wiring_private.h"
#include "PolledTimeout.h" #include "PolledTimeout.h"
extern "C"
{
extern "C" {
#include "twi_util.h" #include "twi_util.h"
#include "ets_sys.h" #include "ets_sys.h"
}; };
@ -57,78 +56,113 @@ static inline __attribute__((always_inline)) bool SCL_READ(const int twi_scl)
return (GPI & (1 << twi_scl)) != 0; return (GPI & (1 << twi_scl)) != 0;
} }
// Implement as a class to reduce code size by allowing access to many global variables with a
// Implement as a class to reduce code size by allowing access to many global variables with a single base pointer // single base pointer
class Twi class Twi
{ {
private: private:
unsigned int preferred_si2c_clock = 100000; unsigned int preferred_si2c_clock = 100000;
uint32_t twi_dcount = 18; uint32_t twi_dcount = 18;
unsigned char twi_sda = 0; unsigned char twi_sda = 0;
unsigned char twi_scl = 0; unsigned char twi_scl = 0;
unsigned char twi_addr = 0; unsigned char twi_addr = 0;
uint32_t twi_clockStretchLimit = 0; uint32_t twi_clockStretchLimit = 0;
// These are int-wide, even though they could all fit in a byte, to reduce code size and avoid any potential // These are int-wide, even though they could all fit in a byte, to reduce code size and avoid
// issues about RmW on packed bytes. The int-wide variations of asm instructions are smaller than the equivalent // any potential issues about RmW on packed bytes. The int-wide variations of asm instructions
// byte-wide ones, and since these emums are used everywhere, the difference adds up fast. There is only a single // are smaller than the equivalent byte-wide ones, and since these emums are used everywhere,
// instance of the class, though, so the extra 12 bytes of RAM used here saves a lot more IRAM. // the difference adds up fast. There is only a single instance of the class, though, so the
volatile enum { TWIPM_UNKNOWN = 0, TWIPM_IDLE, TWIPM_ADDRESSED, TWIPM_WAIT} twip_mode = TWIPM_IDLE; // extra 12 bytes of RAM used here saves a lot more IRAM.
volatile enum { TWIP_UNKNOWN = 0, TWIP_IDLE, TWIP_START, TWIP_SEND_ACK, TWIP_WAIT_ACK, TWIP_WAIT_STOP, TWIP_SLA_W, TWIP_SLA_R, TWIP_REP_START, TWIP_READ, TWIP_STOP, TWIP_REC_ACK, TWIP_READ_ACK, TWIP_RWAIT_ACK, TWIP_WRITE, TWIP_BUS_ERR } twip_state = TWIP_IDLE; volatile enum {
TWIPM_UNKNOWN = 0,
TWIPM_IDLE,
TWIPM_ADDRESSED,
TWIPM_WAIT
} twip_mode
= TWIPM_IDLE;
volatile enum {
TWIP_UNKNOWN = 0,
TWIP_IDLE,
TWIP_START,
TWIP_SEND_ACK,
TWIP_WAIT_ACK,
TWIP_WAIT_STOP,
TWIP_SLA_W,
TWIP_SLA_R,
TWIP_REP_START,
TWIP_READ,
TWIP_STOP,
TWIP_REC_ACK,
TWIP_READ_ACK,
TWIP_RWAIT_ACK,
TWIP_WRITE,
TWIP_BUS_ERR
} twip_state
= TWIP_IDLE;
volatile int twip_status = TW_NO_INFO; volatile int twip_status = TW_NO_INFO;
volatile int bitCount = 0; volatile int bitCount = 0;
volatile uint8_t twi_data = 0x00; volatile uint8_t twi_data = 0x00;
volatile int twi_ack = 0; volatile int twi_ack = 0;
volatile int twi_ack_rec = 0; volatile int twi_ack_rec = 0;
volatile int twi_timeout_ms = 10; volatile int twi_timeout_ms = 10;
volatile enum { TWI_READY = 0, TWI_MRX, TWI_MTX, TWI_SRX, TWI_STX } twi_state = TWI_READY; volatile enum { TWI_READY = 0, TWI_MRX, TWI_MTX, TWI_SRX, TWI_STX } twi_state = TWI_READY;
volatile uint8_t twi_error = 0xFF; volatile uint8_t twi_error = 0xFF;
uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
volatile int twi_txBufferIndex = 0; volatile int twi_txBufferIndex = 0;
volatile int twi_txBufferLength = 0; volatile int twi_txBufferLength = 0;
uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];
volatile int twi_rxBufferIndex = 0; volatile int twi_rxBufferIndex = 0;
void (*twi_onSlaveTransmit)(void); void (*twi_onSlaveTransmit)(void);
void (*twi_onSlaveReceive)(uint8_t*, size_t); void (*twi_onSlaveReceive)(uint8_t*, size_t);
// ETS queue/timer interfaces // ETS queue/timer interfaces
enum { EVENTTASK_QUEUE_SIZE = 1, EVENTTASK_QUEUE_PRIO = 2 }; enum
enum { TWI_SIG_RANGE = 0x00000100, TWI_SIG_RX = 0x00000101, TWI_SIG_TX = 0x00000102 }; {
EVENTTASK_QUEUE_SIZE = 1,
EVENTTASK_QUEUE_PRIO = 2
};
enum
{
TWI_SIG_RANGE = 0x00000100,
TWI_SIG_RX = 0x00000101,
TWI_SIG_TX = 0x00000102
};
ETSEvent eventTaskQueue[EVENTTASK_QUEUE_SIZE]; ETSEvent eventTaskQueue[EVENTTASK_QUEUE_SIZE];
ETSTimer timer; ETSTimer timer;
// Event/IRQ callbacks, so they can't use "this" and need to be static // Event/IRQ callbacks, so they can't use "this" and need to be static
static void IRAM_ATTR onSclChange(void); static void IRAM_ATTR onSclChange(void);
static void IRAM_ATTR onSdaChange(void); static void IRAM_ATTR onSdaChange(void);
static void eventTask(ETSEvent *e); static void eventTask(ETSEvent* e);
static void IRAM_ATTR onTimer(void *unused); static void IRAM_ATTR onTimer(void* unused);
// Allow not linking in the slave code if there is no call to setAddress // Allow not linking in the slave code if there is no call to setAddress
bool _slaveEnabled = false; bool _slaveEnabled = false;
// Internal use functions // Internal use functions
void IRAM_ATTR busywait(unsigned int v); void IRAM_ATTR busywait(unsigned int v);
bool write_start(void); bool write_start(void);
bool write_stop(void); bool write_stop(void);
bool write_bit(bool bit); bool write_bit(bool bit);
bool read_bit(void); bool read_bit(void);
bool write_byte(unsigned char byte); bool write_byte(unsigned char byte);
unsigned char read_byte(bool nack); unsigned char read_byte(bool nack);
void IRAM_ATTR onTwipEvent(uint8_t status); void IRAM_ATTR onTwipEvent(uint8_t status);
// Handle the case where a slave needs to stretch the clock with a time-limited busy wait // Handle the case where a slave needs to stretch the clock with a time-limited busy wait
inline void WAIT_CLOCK_STRETCH() inline void WAIT_CLOCK_STRETCH()
{ {
esp8266::polledTimeout::oneShotFastUs timeout(twi_clockStretchLimit); esp8266::polledTimeout::oneShotFastUs timeout(twi_clockStretchLimit);
esp8266::polledTimeout::periodicFastUs yieldTimeout(5000); esp8266::polledTimeout::periodicFastUs yieldTimeout(5000);
while (!timeout && !SCL_READ(twi_scl)) // outer loop is stretch duration up to stretch limit while (!timeout
&& !SCL_READ(twi_scl)) // outer loop is stretch duration up to stretch limit
{ {
if (yieldTimeout) // inner loop yields every 5ms if (yieldTimeout) // inner loop yields every 5ms
{ {
yield(); yield();
} }
@ -139,19 +173,21 @@ private:
void twi_scl_valley(void); void twi_scl_valley(void);
public: public:
void setClock(unsigned int freq); void setClock(unsigned int freq);
void setClockStretchLimit(uint32_t limit); void setClockStretchLimit(uint32_t limit);
void init(unsigned char sda, unsigned char scl); void init(unsigned char sda, unsigned char scl);
void setAddress(uint8_t address); void setAddress(uint8_t address);
unsigned char writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop); unsigned char writeTo(unsigned char address, unsigned char* buf, unsigned int len,
unsigned char readFrom(unsigned char address, unsigned char* buf, unsigned int len, unsigned char sendStop); unsigned char sendStop);
uint8_t status(); unsigned char readFrom(unsigned char address, unsigned char* buf, unsigned int len,
uint8_t transmit(const uint8_t* data, uint8_t length); unsigned char sendStop);
void attachSlaveRxEvent(void (*function)(uint8_t*, size_t)); uint8_t status();
void attachSlaveTxEvent(void (*function)(void)); uint8_t transmit(const uint8_t* data, uint8_t length);
void attachSlaveRxEvent(void (*function)(uint8_t*, size_t));
void attachSlaveTxEvent(void (*function)(void));
void IRAM_ATTR reply(uint8_t ack); void IRAM_ATTR reply(uint8_t ack);
void IRAM_ATTR releaseBus(void); void IRAM_ATTR releaseBus(void);
void enableSlave(); void enableSlave();
}; };
static Twi twi; static Twi twi;
@ -176,7 +212,8 @@ void Twi::setClock(unsigned int freq)
freq = 400000; freq = 400000;
} }
twi_dcount = (500000000 / freq); // half-cycle period in ns twi_dcount = (500000000 / freq); // half-cycle period in ns
twi_dcount = (1000 * (twi_dcount - 1120)) / 62500; // (half cycle - overhead) / busywait loop time twi_dcount
= (1000 * (twi_dcount - 1120)) / 62500; // (half cycle - overhead) / busywait loop time
#else #else
@ -185,7 +222,8 @@ void Twi::setClock(unsigned int freq)
freq = 800000; freq = 800000;
} }
twi_dcount = (500000000 / freq); // half-cycle period in ns twi_dcount = (500000000 / freq); // half-cycle period in ns
twi_dcount = (1000 * (twi_dcount - 560)) / 31250; // (half cycle - overhead) / busywait loop time twi_dcount
= (1000 * (twi_dcount - 560)) / 31250; // (half cycle - overhead) / busywait loop time
#endif #endif
} }
@ -195,8 +233,6 @@ void Twi::setClockStretchLimit(uint32_t limit)
twi_clockStretchLimit = limit; twi_clockStretchLimit = limit;
} }
void Twi::init(unsigned char sda, unsigned char scl) void Twi::init(unsigned char sda, unsigned char scl)
{ {
// set timer function // set timer function
@ -210,7 +246,7 @@ void Twi::init(unsigned char sda, unsigned char scl)
pinMode(twi_sda, INPUT_PULLUP); pinMode(twi_sda, INPUT_PULLUP);
pinMode(twi_scl, INPUT_PULLUP); pinMode(twi_scl, INPUT_PULLUP);
twi_setClock(preferred_si2c_clock); twi_setClock(preferred_si2c_clock);
twi_setClockStretchLimit(150000L); // default value is 150 mS twi_setClockStretchLimit(150000L); // default value is 150 mS
} }
void Twi::setAddress(uint8_t address) void Twi::setAddress(uint8_t address)
@ -234,7 +270,8 @@ void IRAM_ATTR Twi::busywait(unsigned int v)
unsigned int i; unsigned int i;
for (i = 0; i < v; i++) // loop time is 5 machine cycles: 31.25ns @ 160MHz, 62.5ns @ 80MHz for (i = 0; i < v; i++) // loop time is 5 machine cycles: 31.25ns @ 160MHz, 62.5ns @ 80MHz
{ {
__asm__ __volatile__("nop"); // minimum element to keep GCC from optimizing this function out. __asm__ __volatile__(
"nop"); // minimum element to keep GCC from optimizing this function out.
} }
} }
@ -250,7 +287,8 @@ bool Twi::write_start(void)
// A high-to-low transition on the SDA line while the SCL is high defines a START condition. // A high-to-low transition on the SDA line while the SCL is high defines a START condition.
SDA_LOW(twi_sda); SDA_LOW(twi_sda);
busywait(twi_dcount); busywait(twi_dcount);
// An additional delay between the SCL line high-to-low transition and setting up the SDA line to prevent a STOP condition execute. // An additional delay between the SCL line high-to-low transition and setting up the SDA line
// to prevent a STOP condition execute.
SCL_LOW(twi_scl); SCL_LOW(twi_scl);
busywait(twi_dcount); busywait(twi_dcount);
return true; return true;
@ -308,7 +346,7 @@ bool Twi::write_byte(unsigned char byte)
write_bit(byte & 0x80); write_bit(byte & 0x80);
byte <<= 1; byte <<= 1;
} }
return !read_bit();//NACK/ACK return !read_bit(); // NACK/ACK
} }
unsigned char Twi::read_byte(bool nack) unsigned char Twi::read_byte(bool nack)
@ -323,12 +361,13 @@ unsigned char Twi::read_byte(bool nack)
return byte; return byte;
} }
unsigned char Twi::writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop) unsigned char Twi::writeTo(unsigned char address, unsigned char* buf, unsigned int len,
unsigned char sendStop)
{ {
unsigned int i; unsigned int i;
if (!write_start()) if (!write_start())
{ {
return 4; //line busy return 4; // line busy
} }
if (!write_byte(((address << 1) | 0) & 0xFF)) if (!write_byte(((address << 1) | 0) & 0xFF))
{ {
@ -336,7 +375,7 @@ unsigned char Twi::writeTo(unsigned char address, unsigned char * buf, unsigned
{ {
write_stop(); write_stop();
} }
return 2; //received NACK on transmit of address return 2; // received NACK on transmit of address
} }
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
{ {
@ -346,7 +385,7 @@ unsigned char Twi::writeTo(unsigned char address, unsigned char * buf, unsigned
{ {
write_stop(); write_stop();
} }
return 3;//received NACK on transmit of data return 3; // received NACK on transmit of data
} }
} }
if (sendStop) if (sendStop)
@ -368,12 +407,13 @@ unsigned char Twi::writeTo(unsigned char address, unsigned char * buf, unsigned
return 0; return 0;
} }
unsigned char Twi::readFrom(unsigned char address, unsigned char* buf, unsigned int len, unsigned char sendStop) unsigned char Twi::readFrom(unsigned char address, unsigned char* buf, unsigned int len,
unsigned char sendStop)
{ {
unsigned int i; unsigned int i;
if (!write_start()) if (!write_start())
{ {
return 4; //line busy return 4; // line busy
} }
if (!write_byte(((address << 1) | 1) & 0xFF)) if (!write_byte(((address << 1) | 1) & 0xFF))
{ {
@ -381,7 +421,7 @@ unsigned char Twi::readFrom(unsigned char address, unsigned char* buf, unsigned
{ {
write_stop(); write_stop();
} }
return 2;//received NACK on transmit of address return 2; // received NACK on transmit of address
} }
for (i = 0; i < (len - 1); i++) for (i = 0; i < (len - 1); i++)
{ {
@ -420,21 +460,25 @@ uint8_t Twi::status()
WAIT_CLOCK_STRETCH(); // wait for a slow slave to finish WAIT_CLOCK_STRETCH(); // wait for a slow slave to finish
if (!SCL_READ(twi_scl)) if (!SCL_READ(twi_scl))
{ {
return I2C_SCL_HELD_LOW; // SCL held low by another device, no procedure available to recover return I2C_SCL_HELD_LOW; // SCL held low by another device, no procedure available to
// recover
} }
int clockCount = 20; int clockCount = 20;
while (!SDA_READ(twi_sda) && clockCount-- > 0) // if SDA low, read the bits slaves have to sent to a max while (!SDA_READ(twi_sda)
&& clockCount-- > 0) // if SDA low, read the bits slaves have to sent to a max
{ {
read_bit(); read_bit();
if (!SCL_READ(twi_scl)) if (!SCL_READ(twi_scl))
{ {
return I2C_SCL_HELD_LOW_AFTER_READ; // I2C bus error. SCL held low beyond slave clock stretch time return I2C_SCL_HELD_LOW_AFTER_READ; // I2C bus error. SCL held low beyond slave clock
// stretch time
} }
} }
if (!SDA_READ(twi_sda)) if (!SDA_READ(twi_sda))
{ {
return I2C_SDA_HELD_LOW; // I2C bus error. SDA line held low by slave/another_master after n bits. return I2C_SDA_HELD_LOW; // I2C bus error. SDA line held low by slave/another_master after
// n bits.
} }
return I2C_OK; return I2C_OK;
@ -476,58 +520,57 @@ void Twi::attachSlaveTxEvent(void (*function)(void))
twi_onSlaveTransmit = function; twi_onSlaveTransmit = function;
} }
// DO NOT INLINE, inlining reply() in combination with compiler optimizations causes function breakup into // DO NOT INLINE, inlining reply() in combination with compiler optimizations causes function
// parts and the IRAM_ATTR isn't propagated correctly to all parts, which of course causes crashes. // breakup into parts and the IRAM_ATTR isn't propagated correctly to all parts, which of course
// causes crashes.
// TODO: test with gcc 9.x and if it still fails, disable optimization with -fdisable-ipa-fnsplit // TODO: test with gcc 9.x and if it still fails, disable optimization with -fdisable-ipa-fnsplit
void IRAM_ATTR Twi::reply(uint8_t ack) void IRAM_ATTR Twi::reply(uint8_t ack)
{ {
// transmit master read ready signal, with or without ack // transmit master read ready signal, with or without ack
if (ack) if (ack)
{ {
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); // TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
SCL_HIGH(twi.twi_scl); // _BV(TWINT) SCL_HIGH(twi.twi_scl); // _BV(TWINT)
twi_ack = 1; // _BV(TWEA) twi_ack = 1; // _BV(TWEA)
} }
else else
{ {
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); // TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
SCL_HIGH(twi.twi_scl); // _BV(TWINT) SCL_HIGH(twi.twi_scl); // _BV(TWINT)
twi_ack = 0; // ~_BV(TWEA) twi_ack = 0; // ~_BV(TWEA)
} }
} }
void IRAM_ATTR Twi::releaseBus(void) void IRAM_ATTR Twi::releaseBus(void)
{ {
// release bus // release bus
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); // TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT);
SCL_HIGH(twi.twi_scl); // _BV(TWINT) SCL_HIGH(twi.twi_scl); // _BV(TWINT)
twi_ack = 1; // _BV(TWEA) twi_ack = 1; // _BV(TWEA)
SDA_HIGH(twi.twi_sda); SDA_HIGH(twi.twi_sda);
// update twi state // update twi state
twi_state = TWI_READY; twi_state = TWI_READY;
} }
void IRAM_ATTR Twi::onTwipEvent(uint8_t status) void IRAM_ATTR Twi::onTwipEvent(uint8_t status)
{ {
twip_status = status; twip_status = status;
switch (status) switch (status)
{ {
// Slave Receiver // Slave Receiver
case TW_SR_SLA_ACK: // addressed, returned ack case TW_SR_SLA_ACK: // addressed, returned ack
case TW_SR_GCALL_ACK: // addressed generally, returned ack case TW_SR_GCALL_ACK: // addressed generally, returned ack
case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack
case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack
// enter slave receiver mode // enter slave receiver mode
twi_state = TWI_SRX; twi_state = TWI_SRX;
// indicate that rx buffer can be overwritten and ack // indicate that rx buffer can be overwritten and ack
twi_rxBufferIndex = 0; twi_rxBufferIndex = 0;
reply(1); reply(1);
break; break;
case TW_SR_DATA_ACK: // data received, returned ack case TW_SR_DATA_ACK: // data received, returned ack
case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack
// if there is still room in the rx buffer // if there is still room in the rx buffer
if (twi_rxBufferIndex < TWI_BUFFER_LENGTH) if (twi_rxBufferIndex < TWI_BUFFER_LENGTH)
{ {
@ -541,29 +584,29 @@ void IRAM_ATTR Twi::onTwipEvent(uint8_t status)
reply(0); reply(0);
} }
break; break;
case TW_SR_STOP: // stop or repeated start condition received case TW_SR_STOP: // stop or repeated start condition received
// put a null char after data if there's room // put a null char after data if there's room
if (twi_rxBufferIndex < TWI_BUFFER_LENGTH) if (twi_rxBufferIndex < TWI_BUFFER_LENGTH)
{ {
twi_rxBuffer[twi_rxBufferIndex] = '\0'; twi_rxBuffer[twi_rxBufferIndex] = '\0';
} }
// callback to user-defined callback over event task to allow for non-RAM-residing code // callback to user-defined callback over event task to allow for non-RAM-residing code
//twi_rxBufferLock = true; // This may be necessary // twi_rxBufferLock = true; // This may be necessary
ets_post(EVENTTASK_QUEUE_PRIO, TWI_SIG_RX, twi_rxBufferIndex); ets_post(EVENTTASK_QUEUE_PRIO, TWI_SIG_RX, twi_rxBufferIndex);
// since we submit rx buffer to "wire" library, we can reset it // since we submit rx buffer to "wire" library, we can reset it
twi_rxBufferIndex = 0; twi_rxBufferIndex = 0;
break; break;
case TW_SR_DATA_NACK: // data received, returned nack case TW_SR_DATA_NACK: // data received, returned nack
case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack
// nack back at master // nack back at master
reply(0); reply(0);
break; break;
// Slave Transmitter // Slave Transmitter
case TW_ST_SLA_ACK: // addressed, returned ack case TW_ST_SLA_ACK: // addressed, returned ack
case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack
// enter slave transmitter mode // enter slave transmitter mode
twi_state = TWI_STX; twi_state = TWI_STX;
// ready the tx buffer index for iteration // ready the tx buffer index for iteration
@ -576,7 +619,7 @@ void IRAM_ATTR Twi::onTwipEvent(uint8_t status)
ets_post(EVENTTASK_QUEUE_PRIO, TWI_SIG_TX, 0); ets_post(EVENTTASK_QUEUE_PRIO, TWI_SIG_TX, 0);
break; break;
case TW_ST_DATA_ACK: // byte sent, ack returned case TW_ST_DATA_ACK: // byte sent, ack returned
// copy data to output register // copy data to output register
twi_data = twi_txBuffer[twi_txBufferIndex++]; twi_data = twi_txBuffer[twi_txBufferIndex++];
@ -602,33 +645,32 @@ void IRAM_ATTR Twi::onTwipEvent(uint8_t status)
reply(0); reply(0);
} }
break; break;
case TW_ST_DATA_NACK: // received nack, we are done case TW_ST_DATA_NACK: // received nack, we are done
case TW_ST_LAST_DATA: // received ack, but we are done already! case TW_ST_LAST_DATA: // received ack, but we are done already!
// leave slave receiver state // leave slave receiver state
releaseBus(); releaseBus();
break; break;
// All // All
case TW_NO_INFO: // no state information case TW_NO_INFO: // no state information
break; break;
case TW_BUS_ERROR: // bus error, illegal stop/start case TW_BUS_ERROR: // bus error, illegal stop/start
twi_error = TW_BUS_ERROR; twi_error = TW_BUS_ERROR;
break; break;
} }
} }
void IRAM_ATTR Twi::onTimer(void *unused) void IRAM_ATTR Twi::onTimer(void* unused)
{ {
(void)unused; (void)unused;
twi.releaseBus(); twi.releaseBus();
twi.onTwipEvent(TW_BUS_ERROR); twi.onTwipEvent(TW_BUS_ERROR);
twi.twip_mode = TWIPM_WAIT; twi.twip_mode = TWIPM_WAIT;
twi.twip_state = TWIP_BUS_ERR; twi.twip_state = TWIP_BUS_ERR;
} }
void Twi::eventTask(ETSEvent *e) void Twi::eventTask(ETSEvent* e)
{ {
if (e == NULL) if (e == NULL)
{ {
return; return;
@ -643,7 +685,7 @@ void Twi::eventTask(ETSEvent *e)
if (twi.twi_txBufferLength == 0) if (twi.twi_txBufferLength == 0)
{ {
twi.twi_txBufferLength = 1; twi.twi_txBufferLength = 1;
twi.twi_txBuffer[0] = 0x00; twi.twi_txBuffer[0] = 0x00;
} }
// Initiate transmission // Initiate transmission
@ -663,7 +705,7 @@ void Twi::eventTask(ETSEvent *e)
// compared to the logical-or of all states with the same branch. This removes the need // compared to the logical-or of all states with the same branch. This removes the need
// for a large series of straight-line compares. The biggest win is when multiple states // for a large series of straight-line compares. The biggest win is when multiple states
// all have the same branch (onSdaChange), but for others there is some benefit, still. // all have the same branch (onSdaChange), but for others there is some benefit, still.
#define S2M(x) (1<<(x)) #define S2M(x) (1 << (x))
// Shorthand for if the state is any of the or'd bitmask x // Shorthand for if the state is any of the or'd bitmask x
#define IFSTATE(x) if (twip_state_mask & (x)) #define IFSTATE(x) if (twip_state_mask & (x))
@ -677,7 +719,7 @@ void IRAM_ATTR Twi::onSclChange(void)
sda = SDA_READ(twi.twi_sda); sda = SDA_READ(twi.twi_sda);
scl = SCL_READ(twi.twi_scl); scl = SCL_READ(twi.twi_scl);
twi.twip_status = 0xF8; // reset TWI status twi.twip_status = 0xF8; // reset TWI status
int twip_state_mask = S2M(twi.twip_state); int twip_state_mask = S2M(twi.twip_state);
IFSTATE(S2M(TWIP_START) | S2M(TWIP_REP_START) | S2M(TWIP_SLA_W) | S2M(TWIP_READ)) IFSTATE(S2M(TWIP_START) | S2M(TWIP_REP_START) | S2M(TWIP_SLA_W) | S2M(TWIP_READ))
@ -752,13 +794,13 @@ void IRAM_ATTR Twi::onSclChange(void)
} }
else else
{ {
SCL_LOW(twi.twi_scl); // clock stretching SCL_LOW(twi.twi_scl); // clock stretching
SDA_HIGH(twi.twi_sda); SDA_HIGH(twi.twi_sda);
twi.twip_mode = TWIPM_ADDRESSED; twi.twip_mode = TWIPM_ADDRESSED;
if (!(twi.twi_data & 0x01)) if (!(twi.twi_data & 0x01))
{ {
twi.onTwipEvent(TW_SR_SLA_ACK); twi.onTwipEvent(TW_SR_SLA_ACK);
twi.bitCount = 8; twi.bitCount = 8;
twi.twip_state = TWIP_SLA_W; twi.twip_state = TWIP_SLA_W;
} }
else else
@ -770,18 +812,18 @@ void IRAM_ATTR Twi::onSclChange(void)
} }
else else
{ {
SCL_LOW(twi.twi_scl); // clock stretching SCL_LOW(twi.twi_scl); // clock stretching
SDA_HIGH(twi.twi_sda); SDA_HIGH(twi.twi_sda);
if (!twi.twi_ack) if (!twi.twi_ack)
{ {
twi.onTwipEvent(TW_SR_DATA_NACK); twi.onTwipEvent(TW_SR_DATA_NACK);
twi.twip_mode = TWIPM_WAIT; twi.twip_mode = TWIPM_WAIT;
twi.twip_state = TWIP_WAIT_STOP; twi.twip_state = TWIP_WAIT_STOP;
} }
else else
{ {
twi.onTwipEvent(TW_SR_DATA_ACK); twi.onTwipEvent(TW_SR_DATA_ACK);
twi.bitCount = 8; twi.bitCount = 8;
twi.twip_state = TWIP_READ; twi.twip_state = TWIP_READ;
} }
} }
@ -837,7 +879,7 @@ void IRAM_ATTR Twi::onSclChange(void)
else else
{ {
twi.twi_ack_rec = !sda; twi.twi_ack_rec = !sda;
twi.twip_state = TWIP_RWAIT_ACK; twi.twip_state = TWIP_RWAIT_ACK;
} }
} }
else IFSTATE(S2M(TWIP_RWAIT_ACK)) else IFSTATE(S2M(TWIP_RWAIT_ACK))
@ -848,7 +890,7 @@ void IRAM_ATTR Twi::onSclChange(void)
} }
else else
{ {
SCL_LOW(twi.twi_scl); // clock stretching SCL_LOW(twi.twi_scl); // clock stretching
if (twi.twi_ack && twi.twi_ack_rec) if (twi.twi_ack && twi.twi_ack_rec)
{ {
twi.onTwipEvent(TW_ST_DATA_ACK); twi.onTwipEvent(TW_ST_DATA_ACK);
@ -858,7 +900,7 @@ void IRAM_ATTR Twi::onSclChange(void)
{ {
// we have no more data to send and/or the master doesn't want anymore // we have no more data to send and/or the master doesn't want anymore
twi.onTwipEvent(twi.twi_ack_rec ? TW_ST_LAST_DATA : TW_ST_DATA_NACK); twi.onTwipEvent(twi.twi_ack_rec ? TW_ST_LAST_DATA : TW_ST_DATA_NACK);
twi.twip_mode = TWIPM_WAIT; twi.twip_mode = TWIPM_WAIT;
twi.twip_state = TWIP_WAIT_STOP; twi.twip_state = TWIP_WAIT_STOP;
} }
} }
@ -875,7 +917,7 @@ void IRAM_ATTR Twi::onSdaChange(void)
scl = SCL_READ(twi.twi_scl); scl = SCL_READ(twi.twi_scl);
int twip_state_mask = S2M(twi.twip_state); int twip_state_mask = S2M(twi.twip_state);
if (scl) /* !DATA */ if (scl) /* !DATA */
{ {
IFSTATE(S2M(TWIP_IDLE)) IFSTATE(S2M(TWIP_IDLE))
{ {
@ -886,17 +928,19 @@ void IRAM_ATTR Twi::onSdaChange(void)
else else
{ {
// START // START
twi.bitCount = 8; twi.bitCount = 8;
twi.twip_state = TWIP_START; twi.twip_state = TWIP_START;
ets_timer_arm_new(&twi.timer, twi.twi_timeout_ms, false, true); // Once, ms ets_timer_arm_new(&twi.timer, twi.twi_timeout_ms, false, true); // Once, ms
} }
} }
else IFSTATE(S2M(TWIP_START) | S2M(TWIP_REP_START) | S2M(TWIP_SEND_ACK) | S2M(TWIP_WAIT_ACK) | S2M(TWIP_SLA_R) | S2M(TWIP_REC_ACK) | S2M(TWIP_READ_ACK) | S2M(TWIP_RWAIT_ACK) | S2M(TWIP_WRITE)) else IFSTATE(S2M(TWIP_START) | S2M(TWIP_REP_START) | S2M(TWIP_SEND_ACK) | S2M(TWIP_WAIT_ACK)
| S2M(TWIP_SLA_R) | S2M(TWIP_REC_ACK) | S2M(TWIP_READ_ACK)
| S2M(TWIP_RWAIT_ACK) | S2M(TWIP_WRITE))
{ {
// START or STOP // START or STOP
SDA_HIGH(twi.twi_sda); // Should not be necessary SDA_HIGH(twi.twi_sda); // Should not be necessary
twi.onTwipEvent(TW_BUS_ERROR); twi.onTwipEvent(TW_BUS_ERROR);
twi.twip_mode = TWIPM_WAIT; twi.twip_mode = TWIPM_WAIT;
twi.twip_state = TWIP_BUS_ERR; twi.twip_state = TWIP_BUS_ERR;
} }
else IFSTATE(S2M(TWIP_WAIT_STOP) | S2M(TWIP_BUS_ERR)) else IFSTATE(S2M(TWIP_WAIT_STOP) | S2M(TWIP_BUS_ERR))
@ -904,10 +948,10 @@ void IRAM_ATTR Twi::onSdaChange(void)
if (sda) if (sda)
{ {
// STOP // STOP
SCL_LOW(twi.twi_scl); // generates a low SCL pulse after STOP SCL_LOW(twi.twi_scl); // generates a low SCL pulse after STOP
ets_timer_disarm(&twi.timer); ets_timer_disarm(&twi.timer);
twi.twip_state = TWIP_IDLE; twi.twip_state = TWIP_IDLE;
twi.twip_mode = TWIPM_IDLE; twi.twip_mode = TWIPM_IDLE;
SCL_HIGH(twi.twi_scl); SCL_HIGH(twi.twi_scl);
} }
else else
@ -919,9 +963,9 @@ void IRAM_ATTR Twi::onSdaChange(void)
} }
else else
{ {
twi.bitCount = 8; twi.bitCount = 8;
twi.twip_state = TWIP_REP_START; twi.twip_state = TWIP_REP_START;
ets_timer_arm_new(&twi.timer, twi.twi_timeout_ms, false, true); // Once, ms ets_timer_arm_new(&twi.timer, twi.twi_timeout_ms, false, true); // Once, ms
} }
} }
} }
@ -932,28 +976,28 @@ void IRAM_ATTR Twi::onSdaChange(void)
{ {
// inside byte transfer - error // inside byte transfer - error
twi.onTwipEvent(TW_BUS_ERROR); twi.onTwipEvent(TW_BUS_ERROR);
twi.twip_mode = TWIPM_WAIT; twi.twip_mode = TWIPM_WAIT;
twi.twip_state = TWIP_BUS_ERR; twi.twip_state = TWIP_BUS_ERR;
} }
else else
{ {
// during first bit in byte transfer - ok // during first bit in byte transfer - ok
SCL_LOW(twi.twi_scl); // clock stretching SCL_LOW(twi.twi_scl); // clock stretching
twi.onTwipEvent(TW_SR_STOP); twi.onTwipEvent(TW_SR_STOP);
if (sda) if (sda)
{ {
// STOP // STOP
ets_timer_disarm(&twi.timer); ets_timer_disarm(&twi.timer);
twi.twip_state = TWIP_IDLE; twi.twip_state = TWIP_IDLE;
twi.twip_mode = TWIPM_IDLE; twi.twip_mode = TWIPM_IDLE;
} }
else else
{ {
// START // START
twi.bitCount = 8; twi.bitCount = 8;
ets_timer_arm_new(&twi.timer, twi.twi_timeout_ms, false, true); // Once, ms ets_timer_arm_new(&twi.timer, twi.twi_timeout_ms, false, true); // Once, ms
twi.twip_state = TWIP_REP_START; twi.twip_state = TWIP_REP_START;
twi.twip_mode = TWIPM_IDLE; twi.twip_mode = TWIPM_IDLE;
} }
} }
} }
@ -961,8 +1005,8 @@ void IRAM_ATTR Twi::onSdaChange(void)
} }
// C wrappers for the object, since API is exposed only as C // C wrappers for the object, since API is exposed only as C
extern "C" { extern "C"
{
void twi_init(unsigned char sda, unsigned char scl) void twi_init(unsigned char sda, unsigned char scl)
{ {
return twi.init(sda, scl); return twi.init(sda, scl);
@ -983,12 +1027,14 @@ extern "C" {
twi.setClockStretchLimit(limit); twi.setClockStretchLimit(limit);
} }
uint8_t twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop) uint8_t twi_writeTo(unsigned char address, unsigned char* buf, unsigned int len,
unsigned char sendStop)
{ {
return twi.writeTo(address, buf, len, sendStop); return twi.writeTo(address, buf, len, sendStop);
} }
uint8_t twi_readFrom(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop) uint8_t twi_readFrom(unsigned char address, unsigned char* buf, unsigned int len,
unsigned char sendStop)
{ {
return twi.readFrom(address, buf, len, sendStop); return twi.readFrom(address, buf, len, sendStop);
} }
@ -998,7 +1044,7 @@ extern "C" {
return twi.status(); return twi.status();
} }
uint8_t twi_transmit(const uint8_t * buf, uint8_t len) uint8_t twi_transmit(const uint8_t* buf, uint8_t len)
{ {
return twi.transmit(buf, len); return twi.transmit(buf, len);
} }
@ -1027,5 +1073,4 @@ extern "C" {
{ {
twi.enableSlave(); twi.enableSlave();
} }
}; };

View File

@ -30,7 +30,7 @@ void __iamslow(const char* what)
#endif #endif
IRAM_ATTR IRAM_ATTR
void hexdump(const void *mem, uint32_t len, uint8_t cols) void hexdump(const void* mem, uint32_t len, uint8_t cols)
{ {
const char* src = (const char*)mem; const char* src = (const char*)mem;
os_printf("\n[HEXDUMP] Address: %p len: 0x%X (%d)", src, len, len); os_printf("\n[HEXDUMP] Address: %p len: 0x%X (%d)", src, len, len);

View File

@ -5,44 +5,54 @@
#include <stdint.h> #include <stdint.h>
#ifdef DEBUG_ESP_CORE #ifdef DEBUG_ESP_CORE
#define DEBUGV(fmt, ...) ::printf((PGM_P)PSTR(fmt), ## __VA_ARGS__) #define DEBUGV(fmt, ...) ::printf((PGM_P)PSTR(fmt), ##__VA_ARGS__)
#endif #endif
#ifndef DEBUGV #ifndef DEBUGV
#define DEBUGV(...) do { (void)0; } while (0) #define DEBUGV(...) \
do \
{ \
(void)0; \
} while (0)
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" void hexdump(const void *mem, uint32_t len, uint8_t cols = 16); extern "C" void hexdump(const void* mem, uint32_t len, uint8_t cols = 16);
#else #else
void hexdump(const void *mem, uint32_t len, uint8_t cols); void hexdump(const void* mem, uint32_t len, uint8_t cols);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif
void __unhandled_exception(const char *str) __attribute__((noreturn)); void __unhandled_exception(const char* str) __attribute__((noreturn));
void __panic_func(const char* file, int line, const char* func) __attribute__((noreturn)); void __panic_func(const char* file, int line, const char* func) __attribute__((noreturn));
#define panic() __panic_func(PSTR(__FILE__), __LINE__, __func__) #define panic() __panic_func(PSTR(__FILE__), __LINE__, __func__)
#ifdef DEBUG_ESP_CORE #ifdef DEBUG_ESP_CORE
extern void __iamslow(const char* what); extern void __iamslow(const char* what);
#define IAMSLOW() \ #define IAMSLOW() \
do { \ do \
static bool once = false; \ { \
if (!once) { \ static bool once = false; \
once = true; \ if (!once) \
__iamslow((PGM_P)FPSTR(__FUNCTION__)); \ { \
} \ once = true; \
__iamslow((PGM_P)FPSTR(__FUNCTION__)); \
} \
} while (0) } while (0)
#else #else
#define IAMSLOW() do { (void)0; } while (0) #define IAMSLOW() \
do \
{ \
(void)0; \
} while (0)
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif // ARD_DEBUG_H
#endif//ARD_DEBUG_H

View File

@ -5,7 +5,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
@ -39,7 +39,7 @@ void setup() {
String type; String type;
if (ArduinoOTA.getCommand() == U_FLASH) { if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch"; type = "sketch";
} else { // U_FS } else { // U_FS
type = "filesystem"; type = "filesystem";
} }

View File

@ -5,7 +5,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
@ -14,7 +14,7 @@ const char* host = "OTA-LEDS";
int led_pin = 13; int led_pin = 13;
#define N_DIMMERS 3 #define N_DIMMERS 3
int dimmer_pin[] = {14, 5, 15}; int dimmer_pin[] = { 14, 5, 15 };
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
@ -45,14 +45,14 @@ void setup() {
} }
ArduinoOTA.setHostname(host); ArduinoOTA.setHostname(host);
ArduinoOTA.onStart([]() { // switch off all the PWMs during upgrade ArduinoOTA.onStart([]() { // switch off all the PWMs during upgrade
for (int i = 0; i < N_DIMMERS; i++) { for (int i = 0; i < N_DIMMERS; i++) {
analogWrite(dimmer_pin[i], 0); analogWrite(dimmer_pin[i], 0);
} }
analogWrite(led_pin, 0); analogWrite(led_pin, 0);
}); });
ArduinoOTA.onEnd([]() { // do a fancy thing with our board led at end ArduinoOTA.onEnd([]() { // do a fancy thing with our board led at end
for (int i = 0; i < 30; i++) { for (int i = 0; i < 30; i++) {
analogWrite(led_pin, (i * 100) % 1001); analogWrite(led_pin, (i * 100) % 1001);
delay(50); delay(50);
@ -67,7 +67,6 @@ void setup() {
/* setup the OTA server */ /* setup the OTA server */
ArduinoOTA.begin(); ArduinoOTA.begin();
Serial.println("Ready"); Serial.println("Ready");
} }
void loop() { void loop() {

View File

@ -20,7 +20,7 @@
/* Set these to your desired softAP credentials. They are not configurable at runtime */ /* Set these to your desired softAP credentials. They are not configurable at runtime */
#ifndef APSSID #ifndef APSSID
#define APSSID "ESP_ap" #define APSSID "ESP_ap"
#define APPSK "12345678" #define APPSK "12345678"
#endif #endif
const char *softAP_ssid = APSSID; const char *softAP_ssid = APSSID;
@ -62,7 +62,7 @@ void setup() {
/* You can remove the password parameter if you want the AP to be open. */ /* You can remove the password parameter if you want the AP to be open. */
WiFi.softAPConfig(apIP, apIP, netMsk); WiFi.softAPConfig(apIP, apIP, netMsk);
WiFi.softAP(softAP_ssid, softAP_password); WiFi.softAP(softAP_ssid, softAP_password);
delay(500); // Without delay I've seen the IP address blank delay(500); // Without delay I've seen the IP address blank
Serial.print("AP IP address: "); Serial.print("AP IP address: ");
Serial.println(WiFi.softAPIP()); Serial.println(WiFi.softAPIP());
@ -74,13 +74,13 @@ void setup() {
server.on("/", handleRoot); server.on("/", handleRoot);
server.on("/wifi", handleWifi); server.on("/wifi", handleWifi);
server.on("/wifisave", handleWifiSave); server.on("/wifisave", handleWifiSave);
server.on("/generate_204", handleRoot); //Android captive portal. Maybe not needed. Might be handled by notFound handler. server.on("/generate_204", handleRoot); // Android captive portal. Maybe not needed. Might be handled by notFound handler.
server.on("/fwlink", handleRoot); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. server.on("/fwlink", handleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
server.onNotFound(handleNotFound); server.onNotFound(handleNotFound);
server.begin(); // Web server start server.begin(); // Web server start
Serial.println("HTTP server started"); Serial.println("HTTP server started");
loadCredentials(); // Load WLAN credentials from network loadCredentials(); // Load WLAN credentials from network
connect = strlen(ssid) > 0; // Request WLAN connect if there is a SSID connect = strlen(ssid) > 0; // Request WLAN connect if there is a SSID
} }
void connectWifi() { void connectWifi() {
@ -106,7 +106,7 @@ void loop() {
/* Don't set retry time too low as retry interfere the softAP operation */ /* Don't set retry time too low as retry interfere the softAP operation */
connect = true; connect = true;
} }
if (status != s) { // WLAN status change if (status != s) { // WLAN status change
Serial.print("Status: "); Serial.print("Status: ");
Serial.println(s); Serial.println(s);
status = s; status = s;
@ -130,13 +130,11 @@ void loop() {
WiFi.disconnect(); WiFi.disconnect();
} }
} }
if (s == WL_CONNECTED) { if (s == WL_CONNECTED) { MDNS.update(); }
MDNS.update();
}
} }
// Do work: // Do work:
//DNS // DNS
dnsServer.processNextRequest(); dnsServer.processNextRequest();
//HTTP // HTTP
server.handleClient(); server.handleClient();
} }

View File

@ -1,6 +1,6 @@
/** Handle root or redirect to captive portal */ /** Handle root or redirect to captive portal */
void handleRoot() { void handleRoot() {
if (captivePortal()) { // If caprive portal redirect instead of displaying the page. if (captivePortal()) { // If caprive portal redirect instead of displaying the page.
return; return;
} }
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
@ -8,8 +8,7 @@ void handleRoot() {
server.sendHeader("Expires", "-1"); server.sendHeader("Expires", "-1");
String Page; String Page;
Page += F( Page += F("<!DOCTYPE html><html lang='en'><head>"
"<!DOCTYPE html><html lang='en'><head>"
"<meta name='viewport' content='width=device-width'>" "<meta name='viewport' content='width=device-width'>"
"<title>CaptivePortal</title></head><body>" "<title>CaptivePortal</title></head><body>"
"<h1>HELLO WORLD!!</h1>"); "<h1>HELLO WORLD!!</h1>");
@ -18,8 +17,7 @@ void handleRoot() {
} else { } else {
Page += String(F("<p>You are connected through the wifi network: ")) + ssid + F("</p>"); Page += String(F("<p>You are connected through the wifi network: ")) + ssid + F("</p>");
} }
Page += F( Page += F("<p>You may want to <a href='/wifi'>config the wifi connection</a>.</p>"
"<p>You may want to <a href='/wifi'>config the wifi connection</a>.</p>"
"</body></html>"); "</body></html>");
server.send(200, "text/html", Page); server.send(200, "text/html", Page);
@ -30,8 +28,8 @@ boolean captivePortal() {
if (!isIp(server.hostHeader()) && server.hostHeader() != (String(myHostname) + ".local")) { if (!isIp(server.hostHeader()) && server.hostHeader() != (String(myHostname) + ".local")) {
Serial.println("Request redirected to captive portal"); Serial.println("Request redirected to captive portal");
server.sendHeader("Location", String("http://") + toStringIp(server.client().localIP()), true); server.sendHeader("Location", String("http://") + toStringIp(server.client().localIP()), true);
server.send(302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. server.send(302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
server.client().stop(); // Stop is needed because we sent no content length server.client().stop(); // Stop is needed because we sent no content length
return true; return true;
} }
return false; return false;
@ -44,8 +42,7 @@ void handleWifi() {
server.sendHeader("Expires", "-1"); server.sendHeader("Expires", "-1");
String Page; String Page;
Page += F( Page += F("<!DOCTYPE html><html lang='en'><head>"
"<!DOCTYPE html><html lang='en'><head>"
"<meta name='viewport' content='width=device-width'>" "<meta name='viewport' content='width=device-width'>"
"<title>CaptivePortal</title></head><body>" "<title>CaptivePortal</title></head><body>"
"<h1>Wifi config</h1>"); "<h1>Wifi config</h1>");
@ -54,40 +51,31 @@ void handleWifi() {
} else { } else {
Page += String(F("<p>You are connected through the wifi network: ")) + ssid + F("</p>"); Page += String(F("<p>You are connected through the wifi network: ")) + ssid + F("</p>");
} }
Page += Page += String(F("\r\n<br />"
String(F( "<table><tr><th align='left'>SoftAP config</th></tr>"
"\r\n<br />" "<tr><td>SSID "))
"<table><tr><th align='left'>SoftAP config</th></tr>" + String(softAP_ssid) + F("</td></tr>"
"<tr><td>SSID ")) + "<tr><td>IP ")
String(softAP_ssid) + + toStringIp(WiFi.softAPIP()) + F("</td></tr>"
F("</td></tr>" "</table>"
"<tr><td>IP ") + "\r\n<br />"
toStringIp(WiFi.softAPIP()) + "<table><tr><th align='left'>WLAN config</th></tr>"
F("</td></tr>" "<tr><td>SSID ")
"</table>" + String(ssid) + F("</td></tr>"
"\r\n<br />" "<tr><td>IP ")
"<table><tr><th align='left'>WLAN config</th></tr>" + toStringIp(WiFi.localIP()) + F("</td></tr>"
"<tr><td>SSID ") + "</table>"
String(ssid) + "\r\n<br />"
F("</td></tr>" "<table><tr><th align='left'>WLAN list (refresh if any missing)</th></tr>");
"<tr><td>IP ") +
toStringIp(WiFi.localIP()) +
F("</td></tr>"
"</table>"
"\r\n<br />"
"<table><tr><th align='left'>WLAN list (refresh if any missing)</th></tr>");
Serial.println("scan start"); Serial.println("scan start");
int n = WiFi.scanNetworks(); int n = WiFi.scanNetworks();
Serial.println("scan done"); Serial.println("scan done");
if (n > 0) { if (n > 0) {
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) { Page += String(F("\r\n<tr><td>SSID ")) + WiFi.SSID(i) + ((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? F(" ") : F(" *")) + F(" (") + WiFi.RSSI(i) + F(")</td></tr>"); }
Page += String(F("\r\n<tr><td>SSID ")) + WiFi.SSID(i) + ((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? F(" ") : F(" *")) + F(" (") + WiFi.RSSI(i) + F(")</td></tr>");
}
} else { } else {
Page += F("<tr><td>No WLAN found</td></tr>"); Page += F("<tr><td>No WLAN found</td></tr>");
} }
Page += F( Page += F("</table>"
"</table>"
"\r\n<br /><form method='POST' action='wifisave'><h4>Connect to network:</h4>" "\r\n<br /><form method='POST' action='wifisave'><h4>Connect to network:</h4>"
"<input type='text' placeholder='network' name='n'/>" "<input type='text' placeholder='network' name='n'/>"
"<br /><input type='password' placeholder='password' name='p'/>" "<br /><input type='password' placeholder='password' name='p'/>"
@ -95,7 +83,7 @@ void handleWifi() {
"<p>You may want to <a href='/'>return to the home page</a>.</p>" "<p>You may want to <a href='/'>return to the home page</a>.</p>"
"</body></html>"); "</body></html>");
server.send(200, "text/html", Page); server.send(200, "text/html", Page);
server.client().stop(); // Stop is needed because we sent no content length server.client().stop(); // Stop is needed because we sent no content length
} }
/** Handle the WLAN save form and redirect to WLAN config page again */ /** Handle the WLAN save form and redirect to WLAN config page again */
@ -107,14 +95,14 @@ void handleWifiSave() {
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server.sendHeader("Pragma", "no-cache"); server.sendHeader("Pragma", "no-cache");
server.sendHeader("Expires", "-1"); server.sendHeader("Expires", "-1");
server.send(302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. server.send(302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
server.client().stop(); // Stop is needed because we sent no content length server.client().stop(); // Stop is needed because we sent no content length
saveCredentials(); saveCredentials();
connect = strlen(ssid) > 0; // Request WLAN connect with new credentials if there is a SSID connect = strlen(ssid) > 0; // Request WLAN connect with new credentials if there is a SSID
} }
void handleNotFound() { void handleNotFound() {
if (captivePortal()) { // If caprive portal redirect instead of displaying the error page. if (captivePortal()) { // If caprive portal redirect instead of displaying the error page.
return; return;
} }
String message = F("File Not Found\n\n"); String message = F("File Not Found\n\n");
@ -126,9 +114,7 @@ void handleNotFound() {
message += server.args(); message += server.args();
message += F("\n"); message += F("\n");
for (uint8_t i = 0; i < server.args(); i++) { for (uint8_t i = 0; i < server.args(); i++) { message += String(F(" ")) + server.argName(i) + F(": ") + server.arg(i) + F("\n"); }
message += String(F(" ")) + server.argName(i) + F(": ") + server.arg(i) + F("\n");
}
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server.sendHeader("Pragma", "no-cache"); server.sendHeader("Pragma", "no-cache");
server.sendHeader("Expires", "-1"); server.sendHeader("Expires", "-1");

View File

@ -2,9 +2,7 @@
boolean isIp(String str) { boolean isIp(String str) {
for (size_t i = 0; i < str.length(); i++) { for (size_t i = 0; i < str.length(); i++) {
int c = str.charAt(i); int c = str.charAt(i);
if (c != '.' && (c < '0' || c > '9')) { if (c != '.' && (c < '0' || c > '9')) { return false; }
return false;
}
} }
return true; return true;
} }
@ -12,10 +10,7 @@ boolean isIp(String str) {
/** IP to String? */ /** IP to String? */
String toStringIp(IPAddress ip) { String toStringIp(IPAddress ip) {
String res = ""; String res = "";
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) { res += String((ip >> (8 * i)) & 0xFF) + "."; }
res += String((ip >> (8 * i)) & 0xFF) + ".";
}
res += String(((ip >> 8 * 3)) & 0xFF); res += String(((ip >> 8 * 3)) & 0xFF);
return res; return res;
} }

View File

@ -11,9 +11,7 @@
void setup() { void setup() {
EEPROM.begin(512); EEPROM.begin(512);
// write a 0 to all 512 bytes of the EEPROM // write a 0 to all 512 bytes of the EEPROM
for (int i = 0; i < 512; i++) { for (int i = 0; i < 512; i++) { EEPROM.write(i, 0); }
EEPROM.write(i, 0);
}
// turn the LED on when we're done // turn the LED on when we're done
pinMode(13, OUTPUT); pinMode(13, OUTPUT);
@ -21,5 +19,4 @@ void setup() {
EEPROM.end(); EEPROM.end();
} }
void loop() { void loop() {}
}

View File

@ -32,9 +32,7 @@ void loop() {
// there are only 512 bytes of EEPROM, from 0 to 511, so if we're // there are only 512 bytes of EEPROM, from 0 to 511, so if we're
// on address 512, wrap around to address 0 // on address 512, wrap around to address 0
if (address == 512) { if (address == 512) { address = 0; }
address = 0;
}
delay(500); delay(500);
} }

View File

@ -5,7 +5,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* host = "esp8266-avrisp"; const char* host = "esp8266-avrisp";
@ -20,7 +20,7 @@ void setup() {
Serial.begin(115200); Serial.begin(115200);
Serial.println(""); Serial.println("");
Serial.println("Arduino AVR-ISP over TCP"); Serial.println("Arduino AVR-ISP over TCP");
avrprog.setReset(false); // let the AVR run avrprog.setReset(false); // let the AVR run
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.begin(ssid, pass); WiFi.begin(ssid, pass);
@ -51,17 +51,20 @@ void loop() {
AVRISPState_t new_state = avrprog.update(); AVRISPState_t new_state = avrprog.update();
if (last_state != new_state) { if (last_state != new_state) {
switch (new_state) { switch (new_state) {
case AVRISP_STATE_IDLE: { case AVRISP_STATE_IDLE:
{
Serial.printf("[AVRISP] now idle\r\n"); Serial.printf("[AVRISP] now idle\r\n");
// Use the SPI bus for other purposes // Use the SPI bus for other purposes
break; break;
} }
case AVRISP_STATE_PENDING: { case AVRISP_STATE_PENDING:
{
Serial.printf("[AVRISP] connection pending\r\n"); Serial.printf("[AVRISP] connection pending\r\n");
// Clean up your other purposes and prepare for programming mode // Clean up your other purposes and prepare for programming mode
break; break;
} }
case AVRISP_STATE_ACTIVE: { case AVRISP_STATE_ACTIVE:
{
Serial.printf("[AVRISP] programming mode\r\n"); Serial.printf("[AVRISP] programming mode\r\n");
// Stand by for completion // Stand by for completion
break; break;
@ -70,11 +73,7 @@ void loop() {
last_state = new_state; last_state = new_state;
} }
// Serve the client // Serve the client
if (last_state != AVRISP_STATE_IDLE) { if (last_state != AVRISP_STATE_IDLE) { avrprog.serve(); }
avrprog.serve();
}
if (WiFi.status() == WL_CONNECTED) { if (WiFi.status() == WL_CONNECTED) { MDNS.update(); }
MDNS.update();
}
} }

View File

@ -33,7 +33,6 @@ void setup() {
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFiMulti.addAP("SSID", "PASSWORD"); WiFiMulti.addAP("SSID", "PASSWORD");
} }
void loop() { void loop() {

View File

@ -33,7 +33,6 @@ void setup() {
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFiMulti.addAP("SSID", "PASSWORD"); WiFiMulti.addAP("SSID", "PASSWORD");
} }
void loop() { void loop() {

View File

@ -14,7 +14,7 @@
#include <WiFiClientSecureBearSSL.h> #include <WiFiClientSecureBearSSL.h>
// Fingerprint for demo URL, expires on June 2, 2021, needs to be updated well before this date // Fingerprint for demo URL, expires on June 2, 2021, needs to be updated well before this date
const uint8_t fingerprint[20] = {0x40, 0xaf, 0x00, 0x6b, 0xec, 0x90, 0x22, 0x41, 0x8e, 0xa3, 0xad, 0xfa, 0x1a, 0xe8, 0x25, 0x41, 0x1d, 0x1a, 0x54, 0xb3}; const uint8_t fingerprint[20] = { 0x40, 0xaf, 0x00, 0x6b, 0xec, 0x90, 0x22, 0x41, 0x8e, 0xa3, 0xad, 0xfa, 0x1a, 0xe8, 0x25, 0x41, 0x1d, 0x1a, 0x54, 0xb3 };
ESP8266WiFiMulti WiFiMulti; ESP8266WiFiMulti WiFiMulti;
@ -41,7 +41,7 @@ void loop() {
// wait for WiFi connection // wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) { if ((WiFiMulti.run() == WL_CONNECTED)) {
std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure); std::unique_ptr<BearSSL::WiFiClientSecure> client(new BearSSL::WiFiClientSecure);
client->setFingerprint(fingerprint); client->setFingerprint(fingerprint);
// Or, if you happy to ignore the SSL certificate, then use the following line instead: // Or, if you happy to ignore the SSL certificate, then use the following line instead:

View File

@ -13,36 +13,31 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
const char* ssidPassword = STAPSK; const char* ssidPassword = STAPSK;
const char *username = "admin"; const char* username = "admin";
const char *password = "admin"; const char* password = "admin";
const char *server = "http://httpbin.org"; const char* server = "http://httpbin.org";
const char *uri = "/digest-auth/auth/admin/admin/MD5"; const char* uri = "/digest-auth/auth/admin/admin/MD5";
String exractParam(String& authReq, const String& param, const char delimit) { String exractParam(String& authReq, const String& param, const char delimit) {
int _begin = authReq.indexOf(param); int _begin = authReq.indexOf(param);
if (_begin == -1) { if (_begin == -1) { return ""; }
return "";
}
return authReq.substring(_begin + param.length(), authReq.indexOf(delimit, _begin + param.length())); return authReq.substring(_begin + param.length(), authReq.indexOf(delimit, _begin + param.length()));
} }
String getCNonce(const int len) { String getCNonce(const int len) {
static const char alphanum[] = static const char alphanum[] = "0123456789"
"0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz";
"abcdefghijklmnopqrstuvwxyz";
String s = ""; String s = "";
for (int i = 0; i < len; ++i) { for (int i = 0; i < len; ++i) { s += alphanum[rand() % (sizeof(alphanum) - 1)]; }
s += alphanum[rand() % (sizeof(alphanum) - 1)];
}
return s; return s;
} }
@ -73,8 +68,7 @@ String getDigestAuth(String& authReq, const String& username, const String& pass
md5.calculate(); md5.calculate();
String response = md5.toString(); String response = md5.toString();
String authorization = "Digest username=\"" + username + "\", realm=\"" + realm + "\", nonce=\"" + nonce + String authorization = "Digest username=\"" + username + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", uri=\"" + uri + "\", algorithm=\"MD5\", qop=auth, nc=" + String(nc) + ", cnonce=\"" + cNonce + "\", response=\"" + response + "\"";
"\", uri=\"" + uri + "\", algorithm=\"MD5\", qop=auth, nc=" + String(nc) + ", cnonce=\"" + cNonce + "\", response=\"" + response + "\"";
Serial.println(authorization); Serial.println(authorization);
return authorization; return authorization;
@ -100,7 +94,7 @@ void setup() {
void loop() { void loop() {
WiFiClient client; WiFiClient client;
HTTPClient http; //must be declared after WiFiClient for correct destruction order, because used by http.begin(client,...) HTTPClient http; // must be declared after WiFiClient for correct destruction order, because used by http.begin(client,...)
Serial.print("[HTTP] begin...\n"); Serial.print("[HTTP] begin...\n");
@ -108,7 +102,7 @@ void loop() {
http.begin(client, String(server) + String(uri)); http.begin(client, String(server) + String(uri));
const char *keys[] = {"WWW-Authenticate"}; const char* keys[] = { "WWW-Authenticate" };
http.collectHeaders(keys, 1); http.collectHeaders(keys, 1);
Serial.print("[HTTP] GET...\n"); Serial.print("[HTTP] GET...\n");

View File

@ -20,7 +20,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
void setup() { void setup() {
@ -40,7 +40,6 @@ void setup() {
Serial.println(""); Serial.println("");
Serial.print("Connected! IP address: "); Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
} }
void loop() { void loop() {
@ -52,7 +51,7 @@ void loop() {
Serial.print("[HTTP] begin...\n"); Serial.print("[HTTP] begin...\n");
// configure traged server and url // configure traged server and url
http.begin(client, "http://" SERVER_IP "/postplain/"); //HTTP http.begin(client, "http://" SERVER_IP "/postplain/"); // HTTP
http.addHeader("Content-Type", "application/json"); http.addHeader("Content-Type", "application/json");
Serial.print("[HTTP] POST...\n"); Serial.print("[HTTP] POST...\n");

View File

@ -13,7 +13,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
ESP8266WiFiMulti WiFiMulti; ESP8266WiFiMulti WiFiMulti;
@ -45,7 +45,7 @@ void setup() {
http.begin(client, "http://jigsaw.w3.org/HTTP/connection.html"); http.begin(client, "http://jigsaw.w3.org/HTTP/connection.html");
//http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html"); // http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html");
} }
int pass = 0; int pass = 0;
@ -60,15 +60,13 @@ void loop() {
Serial.printf("[HTTP] GET... code: %d\n", httpCode); Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server // file found at server
if (httpCode == HTTP_CODE_OK) { if (httpCode == HTTP_CODE_OK) { http.writeToStream(&Serial); }
http.writeToStream(&Serial);
}
} else { } else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
// Something went wrong with the connection, try to reconnect // Something went wrong with the connection, try to reconnect
http.end(); http.end();
http.begin(client, "http://jigsaw.w3.org/HTTP/connection.html"); http.begin(client, "http://jigsaw.w3.org/HTTP/connection.html");
//http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html"); // http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html");
} }
if (pass == 10) { if (pass == 10) {

View File

@ -31,7 +31,6 @@ void setup() {
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFiMulti.addAP("SSID", "PASSWORD"); WiFiMulti.addAP("SSID", "PASSWORD");
} }
void loop() { void loop() {
@ -39,13 +38,13 @@ void loop() {
if ((WiFiMulti.run() == WL_CONNECTED)) { if ((WiFiMulti.run() == WL_CONNECTED)) {
WiFiClient client; WiFiClient client;
HTTPClient http; //must be declared after WiFiClient for correct destruction order, because used by http.begin(client,...) HTTPClient http; // must be declared after WiFiClient for correct destruction order, because used by http.begin(client,...)
Serial.print("[HTTP] begin...\n"); Serial.print("[HTTP] begin...\n");
// configure server and url // configure server and url
http.begin(client, "http://jigsaw.w3.org/HTTP/connection.html"); http.begin(client, "http://jigsaw.w3.org/HTTP/connection.html");
//http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html"); // http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html");
Serial.print("[HTTP] GET...\n"); Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header // start connection and send HTTP header
@ -70,23 +69,19 @@ void loop() {
// or "by hand" // or "by hand"
// get tcp stream // get tcp stream
WiFiClient * stream = &client; WiFiClient* stream = &client;
// read all data from server // read all data from server
while (http.connected() && (len > 0 || len == -1)) { while (http.connected() && (len > 0 || len == -1)) {
// read up to 128 byte // read up to 128 byte
int c = stream->readBytes(buff, std::min((size_t)len, sizeof(buff))); int c = stream->readBytes(buff, std::min((size_t)len, sizeof(buff)));
Serial.printf("readBytes: %d\n", c); Serial.printf("readBytes: %d\n", c);
if (!c) { if (!c) { Serial.println("read timeout"); }
Serial.println("read timeout");
}
// write it to Serial // write it to Serial
Serial.write(buff, c); Serial.write(buff, c);
if (len > 0) { if (len > 0) { len -= c; }
len -= c;
}
} }
#endif #endif

View File

@ -31,7 +31,6 @@ void setup() {
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFiMulti.addAP("SSID", "PASSWORD"); WiFiMulti.addAP("SSID", "PASSWORD");
} }
void loop() { void loop() {
@ -43,14 +42,12 @@ void loop() {
bool mfln = client->probeMaxFragmentLength("tls.mbed.org", 443, 1024); bool mfln = client->probeMaxFragmentLength("tls.mbed.org", 443, 1024);
Serial.printf("\nConnecting to https://tls.mbed.org\n"); Serial.printf("\nConnecting to https://tls.mbed.org\n");
Serial.printf("Maximum fragment Length negotiation supported: %s\n", mfln ? "yes" : "no"); Serial.printf("Maximum fragment Length negotiation supported: %s\n", mfln ? "yes" : "no");
if (mfln) { if (mfln) { client->setBufferSizes(1024, 1024); }
client->setBufferSizes(1024, 1024);
}
Serial.print("[HTTPS] begin...\n"); Serial.print("[HTTPS] begin...\n");
// configure server and url // configure server and url
const uint8_t fingerprint[20] = {0x15, 0x77, 0xdc, 0x04, 0x7c, 0x00, 0xf8, 0x70, 0x09, 0x34, 0x24, 0xf4, 0xd3, 0xa1, 0x7a, 0x6c, 0x1e, 0xa3, 0xe0, 0x2a}; const uint8_t fingerprint[20] = { 0x15, 0x77, 0xdc, 0x04, 0x7c, 0x00, 0xf8, 0x70, 0x09, 0x34, 0x24, 0xf4, 0xd3, 0xa1, 0x7a, 0x6c, 0x1e, 0xa3, 0xe0, 0x2a };
client->setFingerprint(fingerprint); client->setFingerprint(fingerprint);
@ -86,16 +83,13 @@ void loop() {
// write it to Serial // write it to Serial
Serial.write(buff, c); Serial.write(buff, c);
if (len > 0) { if (len > 0) { len -= c; }
len -= c;
}
} }
delay(1); delay(1);
} }
Serial.println(); Serial.println();
Serial.print("[HTTPS] connection closed or file end.\n"); Serial.print("[HTTPS] connection closed or file end.\n");
} }
} else { } else {
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str()); Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());

View File

@ -21,7 +21,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* host = "esp8266-webupdate"; const char* host = "esp8266-webupdate";
@ -57,7 +57,7 @@ JfUvYadSYxh3nblvA4OL+iEZiW8NE3hbW6WPXxvS7Euge0uWMPc4uEcnsE0ZVG3m
-----END CERTIFICATE----- -----END CERTIFICATE-----
)EOF"; )EOF";
static const char serverKey[] PROGMEM = R"EOF( static const char serverKey[] PROGMEM = R"EOF(
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA9UoHBtn4oNKXjRgIOQ/rLxK/iI0a8Q5mDxhfuwa9//FkftSI MIIEpQIBAAKCAQEA9UoHBtn4oNKXjRgIOQ/rLxK/iI0a8Q5mDxhfuwa9//FkftSI
IFY8UhGk2YNJpnfKOyYWqbqwuJhIZJ2sEIWp2301OnavuGBrpKOgBJJljgH2l/4Z IFY8UhGk2YNJpnfKOyYWqbqwuJhIZJ2sEIWp2301OnavuGBrpKOgBJJljgH2l/4Z
@ -88,8 +88,7 @@ gz5JWYhbD6c38khSzJb0pNXCo3EuYAVa36kDM96k1BtWuhRS10Q1VXk=
)EOF"; )EOF";
void setup() void setup() {
{
Serial.begin(115200); Serial.begin(115200);
Serial.println(); Serial.println();
@ -97,7 +96,7 @@ void setup()
WiFi.mode(WIFI_AP_STA); WiFi.mode(WIFI_AP_STA);
WiFi.begin(ssid, password); WiFi.begin(ssid, password);
while(WiFi.waitForConnectResult() != WL_CONNECTED){ while (WiFi.waitForConnectResult() != WL_CONNECTED) {
WiFi.begin(ssid, password); WiFi.begin(ssid, password);
Serial.println("WiFi failed, retrying."); Serial.println("WiFi failed, retrying.");
} }
@ -111,13 +110,13 @@ void setup()
httpServer.begin(); httpServer.begin();
MDNS.addService("https", "tcp", 443); MDNS.addService("https", "tcp", 443);
Serial.printf("BearSSLUpdateServer ready!\nOpen https://%s.local%s in "\ Serial.printf("BearSSLUpdateServer ready!\nOpen https://%s.local%s in "
"your browser and login with username '%s' and password "\ "your browser and login with username '%s' and password "
"'%s'\n", host, update_path, update_username, update_password); "'%s'\n",
host, update_path, update_username, update_password);
} }
void loop() void loop() {
{
httpServer.handleClient(); httpServer.handleClient();
MDNS.update(); MDNS.update();
} }

View File

@ -10,7 +10,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* host = "esp8266-webupdate"; const char* host = "esp8266-webupdate";

View File

@ -10,7 +10,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* host = "esp8266-webupdate"; const char* host = "esp8266-webupdate";

View File

@ -62,7 +62,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;

View File

@ -4,7 +4,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;

View File

@ -4,7 +4,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
@ -46,9 +46,7 @@ void setup() {
Serial.printf("Ready!\n"); Serial.printf("Ready!\n");
} else { } else {
Serial.printf("WiFi Failed\n"); Serial.printf("WiFi Failed\n");
while (1) { while (1) { delay(100); }
delay(100);
}
} }
} }

View File

@ -35,7 +35,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char *ssid = STASSID; const char *ssid = STASSID;
@ -69,8 +69,7 @@ void handleRoot() {
</body>\ </body>\
</html>", </html>",
hr, min % 60, sec % 60 hr, min % 60, sec % 60);
);
server.send(200, "text/html", temp); server.send(200, "text/html", temp);
digitalWrite(led, 0); digitalWrite(led, 0);
} }
@ -86,9 +85,7 @@ void handleNotFound() {
message += server.args(); message += server.args();
message += "\n"; message += "\n";
for (uint8_t i = 0; i < server.args(); i++) { for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; }
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message); server.send(404, "text/plain", message);
digitalWrite(led, 0); digitalWrite(led, 0);
@ -133,9 +130,7 @@ void setup(void) {
Serial.print("IP address: "); Serial.print("IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
if (MDNS.begin("esp8266")) { if (MDNS.begin("esp8266")) { Serial.println("MDNS responder started"); }
Serial.println("MDNS responder started");
}
server.on("/", handleRoot); server.on("/", handleRoot);
server.on("/test.svg", drawGraph); server.on("/test.svg", drawGraph);
@ -151,4 +146,3 @@ void loop(void) {
server.handleClient(); server.handleClient();
MDNS.update(); MDNS.update();
} }

View File

@ -72,7 +72,7 @@ SDFSConfig fileSystemConfig = SDFSConfig();
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
@ -122,15 +122,9 @@ void replyServerError(String msg) {
*/ */
String checkForUnsupportedPath(String filename) { String checkForUnsupportedPath(String filename) {
String error = String(); String error = String();
if (!filename.startsWith("/")) { if (!filename.startsWith("/")) { error += F("!NO_LEADING_SLASH! "); }
error += F("!NO_LEADING_SLASH! "); if (filename.indexOf("//") != -1) { error += F("!DOUBLE_SLASH! "); }
} if (filename.endsWith("/")) { error += F("!TRAILING_SLASH! "); }
if (filename.indexOf("//") != -1) {
error += F("!DOUBLE_SLASH! ");
}
if (filename.endsWith("/")) {
error += F("!TRAILING_SLASH! ");
}
return error; return error;
} }
#endif #endif
@ -174,18 +168,12 @@ void handleStatus() {
Also demonstrates the use of chunked responses. Also demonstrates the use of chunked responses.
*/ */
void handleFileList() { void handleFileList() {
if (!fsOK) { if (!fsOK) { return replyServerError(FPSTR(FS_INIT_ERROR)); }
return replyServerError(FPSTR(FS_INIT_ERROR));
}
if (!server.hasArg("dir")) { if (!server.hasArg("dir")) { return replyBadRequest(F("DIR ARG MISSING")); }
return replyBadRequest(F("DIR ARG MISSING"));
}
String path = server.arg("dir"); String path = server.arg("dir");
if (path != "/" && !fileSystem->exists(path)) { if (path != "/" && !fileSystem->exists(path)) { return replyBadRequest("BAD PATH"); }
return replyBadRequest("BAD PATH");
}
DBG_OUTPUT_PORT.println(String("handleFileList: ") + path); DBG_OUTPUT_PORT.println(String("handleFileList: ") + path);
Dir dir = fileSystem->openDir(path); Dir dir = fileSystem->openDir(path);
@ -253,9 +241,7 @@ bool handleFileRead(String path) {
return true; return true;
} }
if (path.endsWith("/")) { if (path.endsWith("/")) { path += "index.htm"; }
path += "index.htm";
}
String contentType; String contentType;
if (server.hasArg("download")) { if (server.hasArg("download")) {
@ -270,9 +256,7 @@ bool handleFileRead(String path) {
} }
if (fileSystem->exists(path)) { if (fileSystem->exists(path)) {
File file = fileSystem->open(path, "r"); File file = fileSystem->open(path, "r");
if (server.streamFile(file, contentType) != file.size()) { if (server.streamFile(file, contentType) != file.size()) { DBG_OUTPUT_PORT.println("Sent less data than expected!"); }
DBG_OUTPUT_PORT.println("Sent less data than expected!");
}
file.close(); file.close();
return true; return true;
} }
@ -309,27 +293,17 @@ String lastExistingParent(String path) {
Move folder | parent of source folder, or remaining ancestor Move folder | parent of source folder, or remaining ancestor
*/ */
void handleFileCreate() { void handleFileCreate() {
if (!fsOK) { if (!fsOK) { return replyServerError(FPSTR(FS_INIT_ERROR)); }
return replyServerError(FPSTR(FS_INIT_ERROR));
}
String path = server.arg("path"); String path = server.arg("path");
if (path.isEmpty()) { if (path.isEmpty()) { return replyBadRequest(F("PATH ARG MISSING")); }
return replyBadRequest(F("PATH ARG MISSING"));
}
#ifdef USE_SPIFFS #ifdef USE_SPIFFS
if (checkForUnsupportedPath(path).length() > 0) { if (checkForUnsupportedPath(path).length() > 0) { return replyServerError(F("INVALID FILENAME")); }
return replyServerError(F("INVALID FILENAME"));
}
#endif #endif
if (path == "/") { if (path == "/") { return replyBadRequest("BAD PATH"); }
return replyBadRequest("BAD PATH"); if (fileSystem->exists(path)) { return replyBadRequest(F("PATH FILE EXISTS")); }
}
if (fileSystem->exists(path)) {
return replyBadRequest(F("PATH FILE EXISTS"));
}
String src = server.arg("src"); String src = server.arg("src");
if (src.isEmpty()) { if (src.isEmpty()) {
@ -338,43 +312,29 @@ void handleFileCreate() {
if (path.endsWith("/")) { if (path.endsWith("/")) {
// Create a folder // Create a folder
path.remove(path.length() - 1); path.remove(path.length() - 1);
if (!fileSystem->mkdir(path)) { if (!fileSystem->mkdir(path)) { return replyServerError(F("MKDIR FAILED")); }
return replyServerError(F("MKDIR FAILED"));
}
} else { } else {
// Create a file // Create a file
File file = fileSystem->open(path, "w"); File file = fileSystem->open(path, "w");
if (file) { if (file) {
file.write((const char *)0); file.write((const char*)0);
file.close(); file.close();
} else { } else {
return replyServerError(F("CREATE FAILED")); return replyServerError(F("CREATE FAILED"));
} }
} }
if (path.lastIndexOf('/') > -1) { if (path.lastIndexOf('/') > -1) { path = path.substring(0, path.lastIndexOf('/')); }
path = path.substring(0, path.lastIndexOf('/'));
}
replyOKWithMsg(path); replyOKWithMsg(path);
} else { } else {
// Source specified: rename // Source specified: rename
if (src == "/") { if (src == "/") { return replyBadRequest("BAD SRC"); }
return replyBadRequest("BAD SRC"); if (!fileSystem->exists(src)) { return replyBadRequest(F("SRC FILE NOT FOUND")); }
}
if (!fileSystem->exists(src)) {
return replyBadRequest(F("SRC FILE NOT FOUND"));
}
DBG_OUTPUT_PORT.println(String("handleFileCreate: ") + path + " from " + src); DBG_OUTPUT_PORT.println(String("handleFileCreate: ") + path + " from " + src);
if (path.endsWith("/")) { if (path.endsWith("/")) { path.remove(path.length() - 1); }
path.remove(path.length() - 1); if (src.endsWith("/")) { src.remove(src.length() - 1); }
} if (!fileSystem->rename(src, path)) { return replyServerError(F("RENAME FAILED")); }
if (src.endsWith("/")) {
src.remove(src.length() - 1);
}
if (!fileSystem->rename(src, path)) {
return replyServerError(F("RENAME FAILED"));
}
replyOKWithMsg(lastExistingParent(src)); replyOKWithMsg(lastExistingParent(src));
} }
} }
@ -403,9 +363,7 @@ void deleteRecursive(String path) {
// Otherwise delete its contents first // Otherwise delete its contents first
Dir dir = fileSystem->openDir(path); Dir dir = fileSystem->openDir(path);
while (dir.next()) { while (dir.next()) { deleteRecursive(path + '/' + dir.fileName()); }
deleteRecursive(path + '/' + dir.fileName());
}
// Then delete the folder itself // Then delete the folder itself
fileSystem->rmdir(path); fileSystem->rmdir(path);
@ -420,19 +378,13 @@ void deleteRecursive(String path) {
Delete folder | parent of deleted folder, or remaining ancestor Delete folder | parent of deleted folder, or remaining ancestor
*/ */
void handleFileDelete() { void handleFileDelete() {
if (!fsOK) { if (!fsOK) { return replyServerError(FPSTR(FS_INIT_ERROR)); }
return replyServerError(FPSTR(FS_INIT_ERROR));
}
String path = server.arg(0); String path = server.arg(0);
if (path.isEmpty() || path == "/") { if (path.isEmpty() || path == "/") { return replyBadRequest("BAD PATH"); }
return replyBadRequest("BAD PATH");
}
DBG_OUTPUT_PORT.println(String("handleFileDelete: ") + path); DBG_OUTPUT_PORT.println(String("handleFileDelete: ") + path);
if (!fileSystem->exists(path)) { if (!fileSystem->exists(path)) { return replyNotFound(FPSTR(FILE_NOT_FOUND)); }
return replyNotFound(FPSTR(FILE_NOT_FOUND));
}
deleteRecursive(path); deleteRecursive(path);
replyOKWithMsg(lastExistingParent(path)); replyOKWithMsg(lastExistingParent(path));
@ -442,37 +394,25 @@ void handleFileDelete() {
Handle a file upload request Handle a file upload request
*/ */
void handleFileUpload() { void handleFileUpload() {
if (!fsOK) { if (!fsOK) { return replyServerError(FPSTR(FS_INIT_ERROR)); }
return replyServerError(FPSTR(FS_INIT_ERROR)); if (server.uri() != "/edit") { return; }
}
if (server.uri() != "/edit") {
return;
}
HTTPUpload& upload = server.upload(); HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) { if (upload.status == UPLOAD_FILE_START) {
String filename = upload.filename; String filename = upload.filename;
// Make sure paths always start with "/" // Make sure paths always start with "/"
if (!filename.startsWith("/")) { if (!filename.startsWith("/")) { filename = "/" + filename; }
filename = "/" + filename;
}
DBG_OUTPUT_PORT.println(String("handleFileUpload Name: ") + filename); DBG_OUTPUT_PORT.println(String("handleFileUpload Name: ") + filename);
uploadFile = fileSystem->open(filename, "w"); uploadFile = fileSystem->open(filename, "w");
if (!uploadFile) { if (!uploadFile) { return replyServerError(F("CREATE FAILED")); }
return replyServerError(F("CREATE FAILED"));
}
DBG_OUTPUT_PORT.println(String("Upload: START, filename: ") + filename); DBG_OUTPUT_PORT.println(String("Upload: START, filename: ") + filename);
} else if (upload.status == UPLOAD_FILE_WRITE) { } else if (upload.status == UPLOAD_FILE_WRITE) {
if (uploadFile) { if (uploadFile) {
size_t bytesWritten = uploadFile.write(upload.buf, upload.currentSize); size_t bytesWritten = uploadFile.write(upload.buf, upload.currentSize);
if (bytesWritten != upload.currentSize) { if (bytesWritten != upload.currentSize) { return replyServerError(F("WRITE FAILED")); }
return replyServerError(F("WRITE FAILED"));
}
} }
DBG_OUTPUT_PORT.println(String("Upload: WRITE, Bytes: ") + upload.currentSize); DBG_OUTPUT_PORT.println(String("Upload: WRITE, Bytes: ") + upload.currentSize);
} else if (upload.status == UPLOAD_FILE_END) { } else if (upload.status == UPLOAD_FILE_END) {
if (uploadFile) { if (uploadFile) { uploadFile.close(); }
uploadFile.close();
}
DBG_OUTPUT_PORT.println(String("Upload: END, Size: ") + upload.totalSize); DBG_OUTPUT_PORT.println(String("Upload: END, Size: ") + upload.totalSize);
} }
} }
@ -484,15 +424,11 @@ void handleFileUpload() {
and if it fails, return a 404 page with debug information and if it fails, return a 404 page with debug information
*/ */
void handleNotFound() { void handleNotFound() {
if (!fsOK) { if (!fsOK) { return replyServerError(FPSTR(FS_INIT_ERROR)); }
return replyServerError(FPSTR(FS_INIT_ERROR));
}
String uri = ESP8266WebServer::urlDecode(server.uri()); // required to read paths with blanks String uri = ESP8266WebServer::urlDecode(server.uri()); // required to read paths with blanks
if (handleFileRead(uri)) { if (handleFileRead(uri)) { return; }
return;
}
// Dump debug data // Dump debug data
String message; String message;
@ -526,9 +462,7 @@ void handleNotFound() {
Otherwise, fails with a 404 page with debug information Otherwise, fails with a 404 page with debug information
*/ */
void handleGetEdit() { void handleGetEdit() {
if (handleFileRead(F("/edit/index.htm"))) { if (handleFileRead(F("/edit/index.htm"))) { return; }
return;
}
#ifdef INCLUDE_FALLBACK_INDEX_HTM #ifdef INCLUDE_FALLBACK_INDEX_HTM
server.sendHeader(F("Content-Encoding"), "gzip"); server.sendHeader(F("Content-Encoding"), "gzip");
@ -536,7 +470,6 @@ void handleGetEdit() {
#else #else
replyNotFound(FPSTR(FILE_NOT_FOUND)); replyNotFound(FPSTR(FILE_NOT_FOUND));
#endif #endif
} }
void setup(void) { void setup(void) {
@ -562,9 +495,7 @@ void setup(void) {
String error = checkForUnsupportedPath(dir.fileName()); String error = checkForUnsupportedPath(dir.fileName());
String fileInfo = dir.fileName() + (dir.isDirectory() ? " [DIR]" : String(" (") + dir.fileSize() + "b)"); String fileInfo = dir.fileName() + (dir.isDirectory() ? " [DIR]" : String(" (") + dir.fileSize() + "b)");
DBG_OUTPUT_PORT.println(error + fileInfo); DBG_OUTPUT_PORT.println(error + fileInfo);
if (error.length() > 0) { if (error.length() > 0) { unsupportedFiles += error + fileInfo + '\n'; }
unsupportedFiles += error + fileInfo + '\n';
}
} }
DBG_OUTPUT_PORT.println(); DBG_OUTPUT_PORT.println();
@ -609,15 +540,15 @@ void setup(void) {
server.on("/edit", HTTP_GET, handleGetEdit); server.on("/edit", HTTP_GET, handleGetEdit);
// Create file // Create file
server.on("/edit", HTTP_PUT, handleFileCreate); server.on("/edit", HTTP_PUT, handleFileCreate);
// Delete file // Delete file
server.on("/edit", HTTP_DELETE, handleFileDelete); server.on("/edit", HTTP_DELETE, handleFileDelete);
// Upload file // Upload file
// - first callback is called after the request has ended with all parsed arguments // - first callback is called after the request has ended with all parsed arguments
// - second callback handles file upload at that location // - second callback handles file upload at that location
server.on("/edit", HTTP_POST, replyOK, handleFileUpload); server.on("/edit", HTTP_POST, replyOK, handleFileUpload);
// Default handler for all URIs not defined above // Default handler for all URIs not defined above
// Use it to read files from filesystem // Use it to read files from filesystem

View File

@ -58,7 +58,7 @@ SDFSConfig fileSystemConfig = SDFSConfig();
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
// Indicate which digital I/Os should be displayed on the chart. // Indicate which digital I/Os should be displayed on the chart.
@ -110,9 +110,7 @@ void replyServerError(String msg) {
bool handleFileRead(String path) { bool handleFileRead(String path) {
DBG_OUTPUT_PORT.println(String("handleFileRead: ") + path); DBG_OUTPUT_PORT.println(String("handleFileRead: ") + path);
if (path.endsWith("/")) { if (path.endsWith("/")) { path += "index.htm"; }
path += "index.htm";
}
String contentType = mime::getContentType(path); String contentType = mime::getContentType(path);
@ -122,9 +120,7 @@ bool handleFileRead(String path) {
} }
if (fileSystem->exists(path)) { if (fileSystem->exists(path)) {
File file = fileSystem->open(path, "r"); File file = fileSystem->open(path, "r");
if (server.streamFile(file, contentType) != file.size()) { if (server.streamFile(file, contentType) != file.size()) { DBG_OUTPUT_PORT.println("Sent less data than expected!"); }
DBG_OUTPUT_PORT.println("Sent less data than expected!");
}
file.close(); file.close();
return true; return true;
} }
@ -139,11 +135,9 @@ bool handleFileRead(String path) {
and if it fails, return a 404 page with debug information and if it fails, return a 404 page with debug information
*/ */
void handleNotFound() { void handleNotFound() {
String uri = ESP8266WebServer::urlDecode(server.uri()); // required to read paths with blanks String uri = ESP8266WebServer::urlDecode(server.uri()); // required to read paths with blanks
if (handleFileRead(uri)) { if (handleFileRead(uri)) { return; }
return;
}
// Dump debug data // Dump debug data
String message; String message;
@ -218,7 +212,7 @@ void setup(void) {
//////////////////////////////// ////////////////////////////////
// WEB SERVER INIT // WEB SERVER INIT
//get heap status, analog input value and all GPIO statuses in one json call // get heap status, analog input value and all GPIO statuses in one json call
server.on("/espData", HTTP_GET, []() { server.on("/espData", HTTP_GET, []() {
String json; String json;
json.reserve(88); json.reserve(88);
@ -249,21 +243,18 @@ void setup(void) {
DBG_OUTPUT_PORT.println(" 0 (OFF): outputs are off and hidden from chart"); DBG_OUTPUT_PORT.println(" 0 (OFF): outputs are off and hidden from chart");
DBG_OUTPUT_PORT.println(" 1 (AUTO): outputs are rotated automatically every second"); DBG_OUTPUT_PORT.println(" 1 (AUTO): outputs are rotated automatically every second");
DBG_OUTPUT_PORT.println(" 2 (MANUAL): outputs can be toggled from the web page"); DBG_OUTPUT_PORT.println(" 2 (MANUAL): outputs can be toggled from the web page");
} }
// Return default GPIO mask, that is all I/Os except SD card ones // Return default GPIO mask, that is all I/Os except SD card ones
unsigned int defaultMask() { unsigned int defaultMask() {
unsigned int mask = 0b11111111111111111; unsigned int mask = 0b11111111111111111;
for (auto pin = 0; pin <= 16; pin++) { for (auto pin = 0; pin <= 16; pin++) {
if (isFlashInterfacePin(pin)) { if (isFlashInterfacePin(pin)) { mask &= ~(1 << pin); }
mask &= ~(1 << pin);
}
} }
return mask; return mask;
} }
int rgbMode = 1; // 0=off - 1=auto - 2=manual int rgbMode = 1; // 0=off - 1=auto - 2=manual
int rgbValue = 0; int rgbValue = 0;
esp8266::polledTimeout::periodicMs timeToChange(1000); esp8266::polledTimeout::periodicMs timeToChange(1000);
bool modeChangeRequested = false; bool modeChangeRequested = false;
@ -278,28 +269,24 @@ void loop(void) {
} }
// see if one second has passed since last change, otherwise stop here // see if one second has passed since last change, otherwise stop here
if (!timeToChange) { if (!timeToChange) { return; }
return;
}
// see if a mode change was requested // see if a mode change was requested
if (modeChangeRequested) { if (modeChangeRequested) {
// increment mode (reset after 2) // increment mode (reset after 2)
rgbMode++; rgbMode++;
if (rgbMode > 2) { if (rgbMode > 2) { rgbMode = 0; }
rgbMode = 0;
}
modeChangeRequested = false; modeChangeRequested = false;
} }
// act according to mode // act according to mode
switch (rgbMode) { switch (rgbMode) {
case 0: // off case 0: // off
gpioMask = defaultMask(); gpioMask = defaultMask();
gpioMask &= ~(1 << 12); // Hide GPIO 12 gpioMask &= ~(1 << 12); // Hide GPIO 12
gpioMask &= ~(1 << 13); // Hide GPIO 13 gpioMask &= ~(1 << 13); // Hide GPIO 13
gpioMask &= ~(1 << 15); // Hide GPIO 15 gpioMask &= ~(1 << 15); // Hide GPIO 15
// reset outputs // reset outputs
digitalWrite(12, 0); digitalWrite(12, 0);
@ -307,14 +294,12 @@ void loop(void) {
digitalWrite(15, 0); digitalWrite(15, 0);
break; break;
case 1: // auto case 1: // auto
gpioMask = defaultMask(); gpioMask = defaultMask();
// increment value (reset after 7) // increment value (reset after 7)
rgbValue++; rgbValue++;
if (rgbValue > 7) { if (rgbValue > 7) { rgbValue = 0; }
rgbValue = 0;
}
// output new values // output new values
digitalWrite(12, rgbValue & 0b001); digitalWrite(12, rgbValue & 0b001);
@ -322,11 +307,10 @@ void loop(void) {
digitalWrite(15, rgbValue & 0b100); digitalWrite(15, rgbValue & 0b100);
break; break;
case 2: // manual case 2: // manual
gpioMask = defaultMask(); gpioMask = defaultMask();
// keep outputs unchanged // keep outputs unchanged
break; break;
} }
} }

View File

@ -5,7 +5,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
@ -31,9 +31,7 @@ void handleNotFound() {
message += "\nArguments: "; message += "\nArguments: ";
message += server.args(); message += server.args();
message += "\n"; message += "\n";
for (uint8_t i = 0; i < server.args(); i++) { for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; }
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message); server.send(404, "text/plain", message);
digitalWrite(led, 0); digitalWrite(led, 0);
} }
@ -57,9 +55,7 @@ void setup(void) {
Serial.print("IP address: "); Serial.print("IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
if (MDNS.begin("esp8266")) { if (MDNS.begin("esp8266")) { Serial.println("MDNS responder started"); }
Serial.println("MDNS responder started");
}
server.on("/", handleRoot); server.on("/", handleRoot);
@ -89,17 +85,17 @@ void setup(void) {
///////////////////////////////////////////////////////// /////////////////////////////////////////////////////////
// Hook examples // Hook examples
server.addHook([](const String & method, const String & url, WiFiClient * client, ESP8266WebServer::ContentTypeFunction contentType) { server.addHook([](const String& method, const String& url, WiFiClient* client, ESP8266WebServer::ContentTypeFunction contentType) {
(void)method; // GET, PUT, ... (void)method; // GET, PUT, ...
(void)url; // example: /root/myfile.html (void)url; // example: /root/myfile.html
(void)client; // the webserver tcp client connection (void)client; // the webserver tcp client connection
(void)contentType; // contentType(".html") => "text/html" (void)contentType; // contentType(".html") => "text/html"
Serial.printf("A useless web hook has passed\n"); Serial.printf("A useless web hook has passed\n");
Serial.printf("(this hook is in 0x%08x area (401x=IRAM 402x=FLASH))\n", esp_get_program_counter()); Serial.printf("(this hook is in 0x%08x area (401x=IRAM 402x=FLASH))\n", esp_get_program_counter());
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE; return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
}); });
server.addHook([](const String&, const String & url, WiFiClient*, ESP8266WebServer::ContentTypeFunction) { server.addHook([](const String&, const String& url, WiFiClient*, ESP8266WebServer::ContentTypeFunction) {
if (url.startsWith("/fail")) { if (url.startsWith("/fail")) {
Serial.printf("An always failing web hook has been triggered\n"); Serial.printf("An always failing web hook has been triggered\n");
return ESP8266WebServer::CLIENT_MUST_STOP; return ESP8266WebServer::CLIENT_MUST_STOP;
@ -107,7 +103,7 @@ void setup(void) {
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE; return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
}); });
server.addHook([](const String&, const String & url, WiFiClient * client, ESP8266WebServer::ContentTypeFunction) { server.addHook([](const String&, const String& url, WiFiClient* client, ESP8266WebServer::ContentTypeFunction) {
if (url.startsWith("/dump")) { if (url.startsWith("/dump")) {
Serial.printf("The dumper web hook is on the run\n"); Serial.printf("The dumper web hook is on the run\n");
@ -137,7 +133,7 @@ void setup(void) {
// check the client connection: it should not immediately be closed // check the client connection: it should not immediately be closed
// (make another '/dump' one to close the first) // (make another '/dump' one to close the first)
Serial.printf("\nTelling server to forget this connection\n"); Serial.printf("\nTelling server to forget this connection\n");
static WiFiClient forgetme = *client; // stop previous one if present and transfer client refcounter static WiFiClient forgetme = *client; // stop previous one if present and transfer client refcounter
return ESP8266WebServer::CLIENT_IS_GIVEN; return ESP8266WebServer::CLIENT_IS_GIVEN;
} }
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE; return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;

View File

@ -18,7 +18,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
@ -50,7 +50,7 @@ JfUvYadSYxh3nblvA4OL+iEZiW8NE3hbW6WPXxvS7Euge0uWMPc4uEcnsE0ZVG3m
-----END CERTIFICATE----- -----END CERTIFICATE-----
)EOF"; )EOF";
static const char serverKey[] PROGMEM = R"EOF( static const char serverKey[] PROGMEM = R"EOF(
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA9UoHBtn4oNKXjRgIOQ/rLxK/iI0a8Q5mDxhfuwa9//FkftSI MIIEpQIBAAKCAQEA9UoHBtn4oNKXjRgIOQ/rLxK/iI0a8Q5mDxhfuwa9//FkftSI
IFY8UhGk2YNJpnfKOyYWqbqwuJhIZJ2sEIWp2301OnavuGBrpKOgBJJljgH2l/4Z IFY8UhGk2YNJpnfKOyYWqbqwuJhIZJ2sEIWp2301OnavuGBrpKOgBJJljgH2l/4Z
@ -89,24 +89,22 @@ void handleRoot() {
digitalWrite(led, 0); digitalWrite(led, 0);
} }
void handleNotFound(){ void handleNotFound() {
digitalWrite(led, 1); digitalWrite(led, 1);
String message = "File Not Found\n\n"; String message = "File Not Found\n\n";
message += "URI: "; message += "URI: ";
message += server.uri(); message += server.uri();
message += "\nMethod: "; message += "\nMethod: ";
message += (server.method() == HTTP_GET)?"GET":"POST"; message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: "; message += "\nArguments: ";
message += server.args(); message += server.args();
message += "\n"; message += "\n";
for (uint8_t i=0; i<server.args(); i++){ for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; }
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message); server.send(404, "text/plain", message);
digitalWrite(led, 0); digitalWrite(led, 0);
} }
void setup(void){ void setup(void) {
pinMode(led, OUTPUT); pinMode(led, OUTPUT);
digitalWrite(led, 0); digitalWrite(led, 0);
Serial.begin(115200); Serial.begin(115200);
@ -127,9 +125,7 @@ void setup(void){
Serial.print("IP address: "); Serial.print("IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
if (MDNS.begin("esp8266")) { if (MDNS.begin("esp8266")) { Serial.println("MDNS responder started"); }
Serial.println("MDNS responder started");
}
server.getServer().setRSACert(new BearSSL::X509List(serverCert), new BearSSL::PrivateKey(serverKey)); server.getServer().setRSACert(new BearSSL::X509List(serverCert), new BearSSL::PrivateKey(serverKey));
@ -138,7 +134,7 @@ void setup(void){
server.on("/", handleRoot); server.on("/", handleRoot);
server.on("/inline", [](){ server.on("/inline", []() {
server.send(200, "text/plain", "this works as well"); server.send(200, "text/plain", "this works as well");
}); });
@ -152,17 +148,20 @@ extern "C" void stack_thunk_dump_stack();
void processKey(Print& out, int hotKey) { void processKey(Print& out, int hotKey) {
switch (hotKey) { switch (hotKey) {
case 'd': { case 'd':
{
HeapSelectDram ephemeral; HeapSelectDram ephemeral;
umm_info(NULL, true); umm_info(NULL, true);
break; break;
} }
case 'i': { case 'i':
{
HeapSelectIram ephemeral; HeapSelectIram ephemeral;
umm_info(NULL, true); umm_info(NULL, true);
break; break;
} }
case 'h': { case 'h':
{
{ {
HeapSelectIram ephemeral; HeapSelectIram ephemeral;
Serial.printf(PSTR("IRAM ESP.getFreeHeap: %u\n"), ESP.getFreeHeap()); Serial.printf(PSTR("IRAM ESP.getFreeHeap: %u\n"), ESP.getFreeHeap());
@ -185,10 +184,8 @@ void processKey(Print& out, int hotKey) {
out.printf_P(PSTR("Restart, ESP.restart(); ...\r\n")); out.printf_P(PSTR("Restart, ESP.restart(); ...\r\n"));
ESP.restart(); ESP.restart();
break; break;
case '\r': case '\r': out.println();
out.println(); case '\n': break;
case '\n':
break;
case '?': case '?':
out.println(); out.println();
out.println(F("Press a key + <enter>")); out.println(F("Press a key + <enter>"));
@ -211,7 +208,7 @@ void processKey(Print& out, int hotKey) {
} }
void loop(void){ void loop(void) {
server.handleClient(); server.handleClient();
MDNS.update(); MDNS.update();
if (Serial.available() > 0) { if (Serial.available() > 0) {

View File

@ -11,7 +11,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
@ -39,13 +39,13 @@ void setup() {
server.on("/", []() { server.on("/", []() {
if (!server.authenticate(www_username, www_password)) if (!server.authenticate(www_username, www_password))
//Basic Auth Method with Custom realm and Failure Response // Basic Auth Method with Custom realm and Failure Response
//return server.requestAuthentication(BASIC_AUTH, www_realm, authFailResponse); // return server.requestAuthentication(BASIC_AUTH, www_realm, authFailResponse);
//Digest Auth Method with realm="Login Required" and empty Failure Response // Digest Auth Method with realm="Login Required" and empty Failure Response
//return server.requestAuthentication(DIGEST_AUTH); // return server.requestAuthentication(DIGEST_AUTH);
//Digest Auth Method with Custom realm and empty Failure Response // Digest Auth Method with Custom realm and empty Failure Response
//return server.requestAuthentication(DIGEST_AUTH, www_realm); // return server.requestAuthentication(DIGEST_AUTH, www_realm);
//Digest Auth Method with Custom realm and Failure Response // Digest Auth Method with Custom realm and Failure Response
{ {
return server.requestAuthentication(DIGEST_AUTH, www_realm, authFailResponse); return server.requestAuthentication(DIGEST_AUTH, www_realm, authFailResponse);
} }

View File

@ -5,7 +5,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;

View File

@ -15,21 +15,21 @@
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <ESP8266WebServerSecure.h> #include <ESP8266WebServerSecure.h>
//Unfortunately it is not possible to have persistent WiFi credentials stored as anything but plain text. Obfuscation would be the only feasible barrier. // Unfortunately it is not possible to have persistent WiFi credentials stored as anything but plain text. Obfuscation would be the only feasible barrier.
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
const char* wifi_pw = STAPSK; const char* wifi_pw = STAPSK;
const String file_credentials = R"(/credentials.txt)"; // LittleFS file name for the saved credentials const String file_credentials = R"(/credentials.txt)"; // LittleFS file name for the saved credentials
const String change_creds = "changecreds"; // Address for a credential change const String change_creds = "changecreds"; // Address for a credential change
//The ESP8266WebServerSecure requires an encryption certificate and matching key. // The ESP8266WebServerSecure requires an encryption certificate and matching key.
//These can generated with the bash script available in the ESP8266 Arduino repository. // These can generated with the bash script available in the ESP8266 Arduino repository.
//These values can be used for testing but are available publicly so should not be used in production. // These values can be used for testing but are available publicly so should not be used in production.
static const char serverCert[] PROGMEM = R"EOF( static const char serverCert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDSzCCAjMCCQD2ahcfZAwXxDANBgkqhkiG9w0BAQsFADCBiTELMAkGA1UEBhMC MIIDSzCCAjMCCQD2ahcfZAwXxDANBgkqhkiG9w0BAQsFADCBiTELMAkGA1UEBhMC
@ -52,7 +52,7 @@ JfUvYadSYxh3nblvA4OL+iEZiW8NE3hbW6WPXxvS7Euge0uWMPc4uEcnsE0ZVG3m
5tAF1D5vAAwA8nfPysumlLsIjohJZo4lgnhB++AlOg== 5tAF1D5vAAwA8nfPysumlLsIjohJZo4lgnhB++AlOg==
-----END CERTIFICATE----- -----END CERTIFICATE-----
)EOF"; )EOF";
static const char serverKey[] PROGMEM = R"EOF( static const char serverKey[] PROGMEM = R"EOF(
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA9UoHBtn4oNKXjRgIOQ/rLxK/iI0a8Q5mDxhfuwa9//FkftSI MIIEpQIBAAKCAQEA9UoHBtn4oNKXjRgIOQ/rLxK/iI0a8Q5mDxhfuwa9//FkftSI
IFY8UhGk2YNJpnfKOyYWqbqwuJhIZJ2sEIWp2301OnavuGBrpKOgBJJljgH2l/4Z IFY8UhGk2YNJpnfKOyYWqbqwuJhIZJ2sEIWp2301OnavuGBrpKOgBJJljgH2l/4Z
@ -84,7 +84,7 @@ gz5JWYhbD6c38khSzJb0pNXCo3EuYAVa36kDM96k1BtWuhRS10Q1VXk=
ESP8266WebServerSecure server(443); ESP8266WebServerSecure server(443);
//These are temporary credentials that will only be used if none are found saved in LittleFS. // These are temporary credentials that will only be used if none are found saved in LittleFS.
String login = "admin"; String login = "admin";
const String realm = "global"; const String realm = "global";
String H1 = ""; String H1 = "";
@ -93,16 +93,16 @@ String authentication_failed = "User authentication has failed.";
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
//Initialize LittleFS to save credentials // Initialize LittleFS to save credentials
if(!LittleFS.begin()){ if (!LittleFS.begin()) {
Serial.println("LittleFS initialization error, programmer flash configured?"); Serial.println("LittleFS initialization error, programmer flash configured?");
ESP.restart(); ESP.restart();
} }
//Attempt to load credentials. If the file does not yet exist, they will be set to the default values above // Attempt to load credentials. If the file does not yet exist, they will be set to the default values above
loadcredentials(); loadcredentials();
//Initialize wifi // Initialize wifi
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.begin(ssid, wifi_pw); WiFi.begin(ssid, wifi_pw);
if (WiFi.waitForConnectResult() != WL_CONNECTED) { if (WiFi.waitForConnectResult() != WL_CONNECTED) {
@ -112,8 +112,8 @@ void setup() {
} }
server.getServer().setRSACert(new BearSSL::X509List(serverCert), new BearSSL::PrivateKey(serverKey)); server.getServer().setRSACert(new BearSSL::X509List(serverCert), new BearSSL::PrivateKey(serverKey));
server.on("/",showcredentialpage); //for this simple example, just show a simple page for changing credentials at the root server.on("/", showcredentialpage); // for this simple example, just show a simple page for changing credentials at the root
server.on("/" + change_creds,handlecredentialchange); //handles submission of credentials from the client server.on("/" + change_creds, handlecredentialchange); // handles submission of credentials from the client
server.onNotFound(redirect); server.onNotFound(redirect);
server.begin(); server.begin();
@ -127,49 +127,48 @@ void loop() {
server.handleClient(); server.handleClient();
} }
//This function redirects home // This function redirects home
void redirect(){ void redirect() {
String url = "https://" + WiFi.localIP().toString(); String url = "https://" + WiFi.localIP().toString();
Serial.println("Redirect called. Redirecting to " + url); Serial.println("Redirect called. Redirecting to " + url);
server.sendHeader("Location", url, true); server.sendHeader("Location", url, true);
Serial.println("Header sent."); Serial.println("Header sent.");
server.send( 302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. server.send(302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
Serial.println("Empty page sent."); Serial.println("Empty page sent.");
server.client().stop(); // Stop is needed because we sent no content length server.client().stop(); // Stop is needed because we sent no content length
Serial.println("Client stopped."); Serial.println("Client stopped.");
} }
//This function checks whether the current session has been authenticated. If not, a request for credentials is sent. // This function checks whether the current session has been authenticated. If not, a request for credentials is sent.
bool session_authenticated() { bool session_authenticated() {
Serial.println("Checking authentication."); Serial.println("Checking authentication.");
if (server.authenticateDigest(login,H1)) { if (server.authenticateDigest(login, H1)) {
Serial.println("Authentication confirmed."); Serial.println("Authentication confirmed.");
return true; return true;
} else { } else {
Serial.println("Not authenticated. Requesting credentials."); Serial.println("Not authenticated. Requesting credentials.");
server.requestAuthentication(DIGEST_AUTH,realm.c_str(),authentication_failed); server.requestAuthentication(DIGEST_AUTH, realm.c_str(), authentication_failed);
redirect(); redirect();
return false; return false;
} }
} }
//This function sends a simple webpage for changing login credentials to the client // This function sends a simple webpage for changing login credentials to the client
void showcredentialpage(){ void showcredentialpage() {
Serial.println("Show credential page called."); Serial.println("Show credential page called.");
if(!session_authenticated()){ if (!session_authenticated()) { return; }
return;
}
Serial.println("Forming credential modification page."); Serial.println("Forming credential modification page.");
String page; String page;
page = R"(<html>)"; page = R"(<html>)";
page+= page +=
R"( R"(
<h2>Login Credentials</h2><br> <h2>Login Credentials</h2><br>
<form action=")" + change_creds + R"(" method="post"> <form action=")"
+ change_creds + R"(" method="post">
Login:<br> Login:<br>
<input type="text" name="login"><br> <input type="text" name="login"><br>
Password:<br> Password:<br>
@ -178,8 +177,7 @@ void showcredentialpage(){
<input type="password" name="password_duplicate"><br> <input type="password" name="password_duplicate"><br>
<p><button type="submit" name="newcredentials">Change Credentials</button></p> <p><button type="submit" name="newcredentials">Change Credentials</button></p>
</form><br> </form><br>
)" )";
;
page += R"(</html>)"; page += R"(</html>)";
@ -188,17 +186,16 @@ void showcredentialpage(){
server.send(200, "text/html", page); server.send(200, "text/html", page);
} }
//Saves credentials to LittleFS // Saves credentials to LittleFS
void savecredentials(String new_login, String new_password) void savecredentials(String new_login, String new_password) {
{ // Set global variables to new values
//Set global variables to new values login = new_login;
login=new_login; H1 = ESP8266WebServer::credentialHash(new_login, realm, new_password);
H1=ESP8266WebServer::credentialHash(new_login,realm,new_password);
//Save new values to LittleFS for loading on next reboot // Save new values to LittleFS for loading on next reboot
Serial.println("Saving credentials."); Serial.println("Saving credentials.");
File f=LittleFS.open(file_credentials,"w"); //open as a brand new file, discard old contents File f = LittleFS.open(file_credentials, "w"); // open as a brand new file, discard old contents
if(f){ if (f) {
Serial.println("Modifying credentials in file system."); Serial.println("Modifying credentials in file system.");
f.println(login); f.println(login);
f.println(H1); f.println(H1);
@ -209,19 +206,18 @@ void savecredentials(String new_login, String new_password)
Serial.println("Credentials saved."); Serial.println("Credentials saved.");
} }
//loads credentials from LittleFS // loads credentials from LittleFS
void loadcredentials() void loadcredentials() {
{
Serial.println("Searching for credentials."); Serial.println("Searching for credentials.");
File f; File f;
f=LittleFS.open(file_credentials,"r"); f = LittleFS.open(file_credentials, "r");
if(f){ if (f) {
Serial.println("Loading credentials from file system."); Serial.println("Loading credentials from file system.");
String mod=f.readString(); //read the file to a String String mod = f.readString(); // read the file to a String
int index_1=mod.indexOf('\n',0); //locate the first line break int index_1 = mod.indexOf('\n', 0); // locate the first line break
int index_2=mod.indexOf('\n',index_1+1); //locate the second line break int index_2 = mod.indexOf('\n', index_1 + 1); // locate the second line break
login=mod.substring(0,index_1-1); //get the first line (excluding the line break) login = mod.substring(0, index_1 - 1); // get the first line (excluding the line break)
H1=mod.substring(index_1+1,index_2-1); //get the second line (excluding the line break) H1 = mod.substring(index_1 + 1, index_2 - 1); // get the second line (excluding the line break)
f.close(); f.close();
} else { } else {
String default_login = "admin"; String default_login = "admin";
@ -229,17 +225,15 @@ void loadcredentials()
Serial.println("None found. Setting to default credentials."); Serial.println("None found. Setting to default credentials.");
Serial.println("user:" + default_login); Serial.println("user:" + default_login);
Serial.println("password:" + default_password); Serial.println("password:" + default_password);
login=default_login; login = default_login;
H1=ESP8266WebServer::credentialHash(default_login,realm,default_password); H1 = ESP8266WebServer::credentialHash(default_login, realm, default_password);
} }
} }
//This function handles a credential change from a client. // This function handles a credential change from a client.
void handlecredentialchange() { void handlecredentialchange() {
Serial.println("Handle credential change called."); Serial.println("Handle credential change called.");
if(!session_authenticated()){ if (!session_authenticated()) { return; }
return;
}
Serial.println("Handling credential change request from client."); Serial.println("Handling credential change request from client.");
@ -247,9 +241,9 @@ void handlecredentialchange() {
String pw1 = server.arg("password"); String pw1 = server.arg("password");
String pw2 = server.arg("password_duplicate"); String pw2 = server.arg("password_duplicate");
if(login != "" && pw1 != "" && pw1 == pw2){ if (login != "" && pw1 != "" && pw1 == pw2) {
savecredentials(login,pw1); savecredentials(login, pw1);
server.send(200, "text/plain", "Credentials updated"); server.send(200, "text/plain", "Credentials updated");
redirect(); redirect();
} else { } else {

View File

@ -8,7 +8,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char *ssid = STASSID; const char *ssid = STASSID;
@ -33,9 +33,7 @@ void setup(void) {
Serial.print("IP address: "); Serial.print("IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
if (MDNS.begin("esp8266")) { if (MDNS.begin("esp8266")) { Serial.println("MDNS responder started"); }
Serial.println("MDNS responder started");
}
server.on(F("/"), []() { server.on(F("/"), []() {
server.send(200, "text/plain", "hello from esp8266!"); server.send(200, "text/plain", "hello from esp8266!");

View File

@ -5,10 +5,10 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
const char* password = STAPSK; const char* password = STAPSK;
ESP8266WebServer server(80); ESP8266WebServer server(80);
@ -62,9 +62,7 @@ void handleForm() {
} else { } else {
digitalWrite(led, 1); digitalWrite(led, 1);
String message = "POST form was:\n"; String message = "POST form was:\n";
for (uint8_t i = 0; i < server.args(); i++) { for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; }
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(200, "text/plain", message); server.send(200, "text/plain", message);
digitalWrite(led, 0); digitalWrite(led, 0);
} }
@ -80,9 +78,7 @@ void handleNotFound() {
message += "\nArguments: "; message += "\nArguments: ";
message += server.args(); message += server.args();
message += "\n"; message += "\n";
for (uint8_t i = 0; i < server.args(); i++) { for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; }
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message); server.send(404, "text/plain", message);
digitalWrite(led, 0); digitalWrite(led, 0);
} }
@ -105,9 +101,7 @@ void setup(void) {
Serial.print("IP address: "); Serial.print("IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
if (MDNS.begin("esp8266")) { if (MDNS.begin("esp8266")) { Serial.println("MDNS responder started"); }
Serial.println("MDNS responder started");
}
server.on("/", handleRoot); server.on("/", handleRoot);

View File

@ -42,11 +42,11 @@ extern "C" {
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char *ssid = STASSID;
const char* password = STAPSK; const char *password = STAPSK;
const unsigned int port = 80; const unsigned int port = 80;
ESP8266WebServer server(port); ESP8266WebServer server(port);
@ -76,20 +76,16 @@ void handleNotFound() {
message += "\nArguments: "; message += "\nArguments: ";
message += server.args(); message += server.args();
message += "\n"; message += "\n";
for (uint8_t i = 0; i < server.args(); i++) { for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; }
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message); server.send(404, "text/plain", message);
} }
void SSEKeepAlive() { void SSEKeepAlive() {
for (uint8_t i = 0; i < SSE_MAX_CHANNELS; i++) { for (uint8_t i = 0; i < SSE_MAX_CHANNELS; i++) {
if (!(subscription[i].clientIP)) { if (!(subscription[i].clientIP)) { continue; }
continue;
}
if (subscription[i].client.connected()) { if (subscription[i].client.connected()) {
Serial.printf_P(PSTR("SSEKeepAlive - client is still listening on channel %d\n"), i); Serial.printf_P(PSTR("SSEKeepAlive - client is still listening on channel %d\n"), i);
subscription[i].client.println(F("event: event\ndata: { \"TYPE\":\"KEEP-ALIVE\" }\n")); // Extra newline required by SSE standard subscription[i].client.println(F("event: event\ndata: { \"TYPE\":\"KEEP-ALIVE\" }\n")); // Extra newline required by SSE standard
} else { } else {
Serial.printf_P(PSTR("SSEKeepAlive - client not listening on channel %d, remove subscription\n"), i); Serial.printf_P(PSTR("SSEKeepAlive - client not listening on channel %d, remove subscription\n"), i);
subscription[i].keepAliveTimer.detach(); subscription[i].keepAliveTimer.detach();
@ -106,15 +102,15 @@ void SSEKeepAlive() {
void SSEHandler(uint8_t channel) { void SSEHandler(uint8_t channel) {
WiFiClient client = server.client(); WiFiClient client = server.client();
SSESubscription &s = subscription[channel]; SSESubscription &s = subscription[channel];
if (s.clientIP != client.remoteIP()) { // IP addresses don't match, reject this client if (s.clientIP != client.remoteIP()) { // IP addresses don't match, reject this client
Serial.printf_P(PSTR("SSEHandler - unregistered client with IP %s tries to listen\n"), server.client().remoteIP().toString().c_str()); Serial.printf_P(PSTR("SSEHandler - unregistered client with IP %s tries to listen\n"), server.client().remoteIP().toString().c_str());
return handleNotFound(); return handleNotFound();
} }
client.setNoDelay(true); client.setNoDelay(true);
client.setSync(true); client.setSync(true);
Serial.printf_P(PSTR("SSEHandler - registered client with IP %s is listening\n"), IPAddress(s.clientIP).toString().c_str()); Serial.printf_P(PSTR("SSEHandler - registered client with IP %s is listening\n"), IPAddress(s.clientIP).toString().c_str());
s.client = client; // capture SSE server client connection s.client = client; // capture SSE server client connection
server.setContentLength(CONTENT_LENGTH_UNKNOWN); // the payload can go on forever server.setContentLength(CONTENT_LENGTH_UNKNOWN); // the payload can go on forever
server.sendContent_P(PSTR("HTTP/1.1 200 OK\nContent-Type: text/event-stream;\nConnection: keep-alive\nCache-Control: no-cache\nAccess-Control-Allow-Origin: *\n\n")); server.sendContent_P(PSTR("HTTP/1.1 200 OK\nContent-Type: text/event-stream;\nConnection: keep-alive\nCache-Control: no-cache\nAccess-Control-Allow-Origin: *\n\n"));
s.keepAliveTimer.attach_scheduled(30.0, SSEKeepAlive); // Refresh time every 30s for demo s.keepAliveTimer.attach_scheduled(30.0, SSEKeepAlive); // Refresh time every 30s for demo
} }
@ -122,28 +118,20 @@ void SSEHandler(uint8_t channel) {
void handleAll() { void handleAll() {
const char *uri = server.uri().c_str(); const char *uri = server.uri().c_str();
const char *restEvents = PSTR("/rest/events/"); const char *restEvents = PSTR("/rest/events/");
if (strncmp_P(uri, restEvents, strlen_P(restEvents))) { if (strncmp_P(uri, restEvents, strlen_P(restEvents))) { return handleNotFound(); }
return handleNotFound(); uri += strlen_P(restEvents); // Skip the "/rest/events/" and get to the channel number
}
uri += strlen_P(restEvents); // Skip the "/rest/events/" and get to the channel number
unsigned int channel = atoi(uri); unsigned int channel = atoi(uri);
if (channel < SSE_MAX_CHANNELS) { if (channel < SSE_MAX_CHANNELS) { return SSEHandler(channel); }
return SSEHandler(channel);
}
handleNotFound(); handleNotFound();
}; };
void SSEBroadcastState(const char *sensorName, unsigned short prevSensorValue, unsigned short sensorValue) { void SSEBroadcastState(const char *sensorName, unsigned short prevSensorValue, unsigned short sensorValue) {
for (uint8_t i = 0; i < SSE_MAX_CHANNELS; i++) { for (uint8_t i = 0; i < SSE_MAX_CHANNELS; i++) {
if (!(subscription[i].clientIP)) { if (!(subscription[i].clientIP)) { continue; }
continue;
}
String IPaddrstr = IPAddress(subscription[i].clientIP).toString(); String IPaddrstr = IPAddress(subscription[i].clientIP).toString();
if (subscription[i].client.connected()) { if (subscription[i].client.connected()) {
Serial.printf_P(PSTR("broadcast status change to client IP %s on channel %d for %s with new state %d\n"), Serial.printf_P(PSTR("broadcast status change to client IP %s on channel %d for %s with new state %d\n"), IPaddrstr.c_str(), i, sensorName, sensorValue);
IPaddrstr.c_str(), i, sensorName, sensorValue); subscription[i].client.printf_P(PSTR("event: event\ndata: {\"TYPE\":\"STATE\", \"%s\":{\"state\":%d, \"prevState\":%d}}\n\n"), sensorName, sensorValue, prevSensorValue);
subscription[i].client.printf_P(PSTR("event: event\ndata: {\"TYPE\":\"STATE\", \"%s\":{\"state\":%d, \"prevState\":%d}}\n\n"),
sensorName, sensorValue, prevSensorValue);
} else { } else {
Serial.printf_P(PSTR("SSEBroadcastState - client %s registered on channel %d but not listening\n"), IPaddrstr.c_str(), i); Serial.printf_P(PSTR("SSEBroadcastState - client %s registered on channel %d but not listening\n"), IPaddrstr.c_str(), i);
} }
@ -152,7 +140,7 @@ void SSEBroadcastState(const char *sensorName, unsigned short prevSensorValue, u
// Simulate sensors // Simulate sensors
void updateSensor(sensorType &sensor) { void updateSensor(sensorType &sensor) {
unsigned short newVal = (unsigned short)RANDOM_REG32; // (not so good) random value for the sensor unsigned short newVal = (unsigned short)RANDOM_REG32; // (not so good) random value for the sensor
Serial.printf_P(PSTR("update sensor %s - previous state: %d, new state: %d\n"), sensor.name, sensor.value, newVal); Serial.printf_P(PSTR("update sensor %s - previous state: %d, new state: %d\n"), sensor.name, sensor.value, newVal);
if (sensor.value != newVal) { if (sensor.value != newVal) {
SSEBroadcastState(sensor.name, sensor.value, newVal); // only broadcast if state is different SSEBroadcastState(sensor.name, sensor.value, newVal); // only broadcast if state is different
@ -167,7 +155,7 @@ void handleSubscribe() {
} }
uint8_t channel; uint8_t channel;
IPAddress clientIP = server.client().remoteIP(); // get IP address of client IPAddress clientIP = server.client().remoteIP(); // get IP address of client
String SSEurl = F("http://"); String SSEurl = F("http://");
SSEurl += WiFi.localIP().toString(); SSEurl += WiFi.localIP().toString();
SSEurl += F(":"); SSEurl += F(":");
@ -176,14 +164,12 @@ void handleSubscribe() {
SSEurl += F("/rest/events/"); SSEurl += F("/rest/events/");
++subscriptionCount; ++subscriptionCount;
for (channel = 0; channel < SSE_MAX_CHANNELS; channel++) // Find first free slot for (channel = 0; channel < SSE_MAX_CHANNELS; channel++) // Find first free slot
if (!subscription[channel].clientIP) { if (!subscription[channel].clientIP) { break; }
break; subscription[channel] = { clientIP, server.client(), Ticker() };
}
subscription[channel] = {clientIP, server.client(), Ticker()};
SSEurl += channel; SSEurl += channel;
Serial.printf_P(PSTR("Allocated channel %d, on uri %s\n"), channel, SSEurl.substring(offset).c_str()); Serial.printf_P(PSTR("Allocated channel %d, on uri %s\n"), channel, SSEurl.substring(offset).c_str());
//server.on(SSEurl.substring(offset), std::bind(SSEHandler, &(subscription[channel]))); // server.on(SSEurl.substring(offset), std::bind(SSEHandler, &(subscription[channel])));
Serial.printf_P(PSTR("subscription for client IP %s: event bus location: %s\n"), clientIP.toString().c_str(), SSEurl.c_str()); Serial.printf_P(PSTR("subscription for client IP %s: event bus location: %s\n"), clientIP.toString().c_str(), SSEurl.c_str());
server.send_P(200, "text/plain", SSEurl.c_str()); server.send_P(200, "text/plain", SSEurl.c_str());
} }
@ -200,16 +186,14 @@ void setup(void) {
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password); WiFi.begin(ssid, password);
Serial.println(""); Serial.println("");
while (WiFi.status() != WL_CONNECTED) { // Wait for connection while (WiFi.status() != WL_CONNECTED) { // Wait for connection
delay(500); delay(500);
Serial.print("."); Serial.print(".");
} }
Serial.printf_P(PSTR("\nConnected to %s with IP address: %s\n"), ssid, WiFi.localIP().toString().c_str()); Serial.printf_P(PSTR("\nConnected to %s with IP address: %s\n"), ssid, WiFi.localIP().toString().c_str());
if (MDNS.begin("esp8266")) { if (MDNS.begin("esp8266")) { Serial.println("MDNS responder started"); }
Serial.println("MDNS responder started");
}
startServers(); // start web and SSE servers startServers(); // start web and SSE servers
sensor[0].name = "sensorA"; sensor[0].name = "sensorA";
sensor[1].name = "sensorB"; sensor[1].name = "sensorB";
updateSensor(sensor[0]); updateSensor(sensor[0]);

View File

@ -4,7 +4,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
@ -12,7 +12,7 @@ const char* password = STAPSK;
ESP8266WebServer server(80); ESP8266WebServer server(80);
//Check if header is present and correct // Check if header is present and correct
bool is_authenticated() { bool is_authenticated() {
Serial.println("Enter is_authenticated"); Serial.println("Enter is_authenticated");
if (server.hasHeader("Cookie")) { if (server.hasHeader("Cookie")) {
@ -28,7 +28,7 @@ bool is_authenticated() {
return false; return false;
} }
//login page, also called for disconnect // login page, also called for disconnect
void handleLogin() { void handleLogin() {
String msg; String msg;
if (server.hasHeader("Cookie")) { if (server.hasHeader("Cookie")) {
@ -45,7 +45,7 @@ void handleLogin() {
return; return;
} }
if (server.hasArg("USERNAME") && server.hasArg("PASSWORD")) { if (server.hasArg("USERNAME") && server.hasArg("PASSWORD")) {
if (server.arg("USERNAME") == "admin" && server.arg("PASSWORD") == "admin") { if (server.arg("USERNAME") == "admin" && server.arg("PASSWORD") == "admin") {
server.sendHeader("Location", "/"); server.sendHeader("Location", "/");
server.sendHeader("Cache-Control", "no-cache"); server.sendHeader("Cache-Control", "no-cache");
server.sendHeader("Set-Cookie", "ESPSESSIONID=1"); server.sendHeader("Set-Cookie", "ESPSESSIONID=1");
@ -64,7 +64,7 @@ void handleLogin() {
server.send(200, "text/html", content); server.send(200, "text/html", content);
} }
//root page can be accessed only if authentication is ok // root page can be accessed only if authentication is ok
void handleRoot() { void handleRoot() {
Serial.println("Enter handleRoot"); Serial.println("Enter handleRoot");
String header; String header;
@ -75,14 +75,12 @@ void handleRoot() {
return; return;
} }
String content = "<html><body><H2>hello, you successfully connected to esp8266!</H2><br>"; String content = "<html><body><H2>hello, you successfully connected to esp8266!</H2><br>";
if (server.hasHeader("User-Agent")) { if (server.hasHeader("User-Agent")) { content += "the user agent used is : " + server.header("User-Agent") + "<br><br>"; }
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>"; content += "You can access this page until you <a href=\"/login?DISCONNECT=YES\">disconnect</a></body></html>";
server.send(200, "text/html", content); server.send(200, "text/html", content);
} }
//no need authentication // no need authentication
void handleNotFound() { void handleNotFound() {
String message = "File Not Found\n\n"; String message = "File Not Found\n\n";
message += "URI: "; message += "URI: ";
@ -92,9 +90,7 @@ void handleNotFound() {
message += "\nArguments: "; message += "\nArguments: ";
message += server.args(); message += server.args();
message += "\n"; message += "\n";
for (uint8_t i = 0; i < server.args(); i++) { for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; }
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message); server.send(404, "text/plain", message);
} }
@ -123,7 +119,7 @@ void setup(void) {
}); });
server.onNotFound(handleNotFound); server.onNotFound(handleNotFound);
//ask server to track these headers // ask server to track these headers
server.collectHeaders("User-Agent", "Cookie"); server.collectHeaders("User-Agent", "Cookie");
server.begin(); server.begin();
Serial.println("HTTP server started"); Serial.println("HTTP server started");

View File

@ -9,10 +9,10 @@
#include <Arduino.h> #include <Arduino.h>
#include <ESP8266WebServer.h> #include <ESP8266WebServer.h>
#include "secrets.h" // add WLAN Credentials in here. #include "secrets.h" // add WLAN Credentials in here.
#include <FS.h> // File System for Web Server Files #include <FS.h> // File System for Web Server Files
#include <LittleFS.h> // This file system is used. #include <LittleFS.h> // This file system is used.
// mark parameters not used in example // mark parameters not used in example
#define UNUSED __attribute__((unused)) #define UNUSED __attribute__((unused))
@ -41,13 +41,11 @@ void handleRedirect() {
TRACE("Redirect..."); TRACE("Redirect...");
String url = "/index.htm"; String url = "/index.htm";
if (!LittleFS.exists(url)) { if (!LittleFS.exists(url)) { url = "/$update.htm"; }
url = "/$update.htm";
}
server.sendHeader("Location", url, true); server.sendHeader("Location", url, true);
server.send(302); server.send(302);
} // handleRedirect() } // handleRedirect()
// This function is called when the WebServer was requested to list all existing files in the filesystem. // This function is called when the WebServer was requested to list all existing files in the filesystem.
@ -58,20 +56,18 @@ void handleListFiles() {
result += "[\n"; result += "[\n";
while (dir.next()) { while (dir.next()) {
if (result.length() > 4) { if (result.length() > 4) { result += ","; }
result += ",";
}
result += " {"; result += " {";
result += " \"name\": \"" + dir.fileName() + "\", "; result += " \"name\": \"" + dir.fileName() + "\", ";
result += " \"size\": " + String(dir.fileSize()) + ", "; result += " \"size\": " + String(dir.fileSize()) + ", ";
result += " \"time\": " + String(dir.fileTime()); result += " \"time\": " + String(dir.fileTime());
result += " }\n"; result += " }\n";
// jc.addProperty("size", dir.fileSize()); // jc.addProperty("size", dir.fileSize());
} // while } // while
result += "]"; result += "]";
server.sendHeader("Cache-Control", "no-cache"); server.sendHeader("Cache-Control", "no-cache");
server.send(200, "text/javascript; charset=utf-8", result); server.send(200, "text/javascript; charset=utf-8", result);
} // handleListFiles() } // handleListFiles()
// This function is called when the sysInfo service was requested. // This function is called when the sysInfo service was requested.
@ -90,96 +86,84 @@ void handleSysInfo() {
server.sendHeader("Cache-Control", "no-cache"); server.sendHeader("Cache-Control", "no-cache");
server.send(200, "text/javascript; charset=utf-8", result); server.send(200, "text/javascript; charset=utf-8", result);
} // handleSysInfo() } // handleSysInfo()
// ===== Request Handler class used to answer more complex requests ===== // ===== Request Handler class used to answer more complex requests =====
// The FileServerHandler is registered to the web server to support DELETE and UPLOAD of files into the filesystem. // The FileServerHandler is registered to the web server to support DELETE and UPLOAD of files into the filesystem.
class FileServerHandler : public RequestHandler { class FileServerHandler : public RequestHandler {
public: public:
// @brief Construct a new File Server Handler object // @brief Construct a new File Server Handler object
// @param fs The file system to be used. // @param fs The file system to be used.
// @param path Path to the root folder in the file system that is used for serving static data down and upload. // @param path Path to the root folder in the file system that is used for serving static data down and upload.
// @param cache_header Cache Header to be used in replies. // @param cache_header Cache Header to be used in replies.
FileServerHandler() { FileServerHandler() {
TRACE("FileServerHandler is registered\n"); TRACE("FileServerHandler is registered\n");
} }
// @brief check incoming request. Can handle POST for uploads and DELETE. // @brief check incoming request. Can handle POST for uploads and DELETE.
// @param requestMethod method of the http request line. // @param requestMethod method of the http request line.
// @param requestUri request ressource from the http request line. // @param requestUri request ressource from the http request line.
// @return true when method can be handled. // @return true when method can be handled.
bool canHandle(HTTPMethod requestMethod, const String UNUSED &_uri) override { bool canHandle(HTTPMethod requestMethod, const String UNUSED &_uri) override {
return ((requestMethod == HTTP_POST) || (requestMethod == HTTP_DELETE)); return ((requestMethod == HTTP_POST) || (requestMethod == HTTP_DELETE));
} // canHandle() } // canHandle()
bool canUpload(const String &uri) override { bool canUpload(const String &uri) override {
// only allow upload on root fs level. // only allow upload on root fs level.
return (uri == "/"); return (uri == "/");
} // canUpload() } // canUpload()
bool handle(ESP8266WebServer &server, HTTPMethod requestMethod, const String &requestUri) override { bool handle(ESP8266WebServer &server, HTTPMethod requestMethod, const String &requestUri) override {
// ensure that filename starts with '/' // ensure that filename starts with '/'
String fName = requestUri; String fName = requestUri;
if (!fName.startsWith("/")) { if (!fName.startsWith("/")) { fName = "/" + fName; }
fName = "/" + fName;
}
if (requestMethod == HTTP_POST) { if (requestMethod == HTTP_POST) {
// all done in upload. no other forms. // all done in upload. no other forms.
} else if (requestMethod == HTTP_DELETE) { } else if (requestMethod == HTTP_DELETE) {
if (LittleFS.exists(fName)) { if (LittleFS.exists(fName)) { LittleFS.remove(fName); }
LittleFS.remove(fName); } // if
}
} // if
server.send(200); // all done. server.send(200); // all done.
return (true); return (true);
} // handle() } // handle()
// uploading process // uploading process
void upload(ESP8266WebServer UNUSED &server, const String UNUSED &_requestUri, HTTPUpload &upload) override { void upload(ESP8266WebServer UNUSED &server, const String UNUSED &_requestUri, HTTPUpload &upload) override {
// ensure that filename starts with '/' // ensure that filename starts with '/'
String fName = upload.filename; String fName = upload.filename;
if (!fName.startsWith("/")) { if (!fName.startsWith("/")) { fName = "/" + fName; }
fName = "/" + fName;
}
if (upload.status == UPLOAD_FILE_START) { if (upload.status == UPLOAD_FILE_START) {
// Open the file // Open the file
if (LittleFS.exists(fName)) { if (LittleFS.exists(fName)) { LittleFS.remove(fName); } // if
LittleFS.remove(fName); _fsUploadFile = LittleFS.open(fName, "w");
} // if
_fsUploadFile = LittleFS.open(fName, "w");
} else if (upload.status == UPLOAD_FILE_WRITE) { } else if (upload.status == UPLOAD_FILE_WRITE) {
// Write received bytes // Write received bytes
if (_fsUploadFile) { if (_fsUploadFile) { _fsUploadFile.write(upload.buf, upload.currentSize); }
_fsUploadFile.write(upload.buf, upload.currentSize);
}
} else if (upload.status == UPLOAD_FILE_END) { } else if (upload.status == UPLOAD_FILE_END) {
// Close the file // Close the file
if (_fsUploadFile) { if (_fsUploadFile) { _fsUploadFile.close(); }
_fsUploadFile.close(); } // if
} } // upload()
} // if
} // upload()
protected: protected:
File _fsUploadFile; File _fsUploadFile;
}; };
// Setup everything to make the webserver work. // Setup everything to make the webserver work.
void setup(void) { void setup(void) {
delay(3000); // wait for serial monitor to start completely. delay(3000); // wait for serial monitor to start completely.
// Use Serial port for some trace information from the example // Use Serial port for some trace information from the example
Serial.begin(115200); Serial.begin(115200);
@ -250,12 +234,12 @@ void setup(void) {
server.begin(); server.begin();
TRACE("hostname=%s\n", WiFi.getHostname()); TRACE("hostname=%s\n", WiFi.getHostname());
} // setup } // setup
// run the server... // run the server...
void loop(void) { void loop(void) {
server.handleClient(); server.handleClient();
} // loop() } // loop()
// end. // end.

View File

@ -9,7 +9,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* host = "esp8266-webupdate"; const char* host = "esp8266-webupdate";
@ -31,34 +31,36 @@ void setup(void) {
server.sendHeader("Connection", "close"); server.sendHeader("Connection", "close");
server.send(200, "text/html", serverIndex); server.send(200, "text/html", serverIndex);
}); });
server.on("/update", HTTP_POST, []() { server.on(
server.sendHeader("Connection", "close"); "/update", HTTP_POST, []() {
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); server.sendHeader("Connection", "close");
ESP.restart(); server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
}, []() { ESP.restart();
HTTPUpload& upload = server.upload(); },
if (upload.status == UPLOAD_FILE_START) { []() {
Serial.setDebugOutput(true); HTTPUpload& upload = server.upload();
WiFiUDP::stopAll(); if (upload.status == UPLOAD_FILE_START) {
Serial.printf("Update: %s\n", upload.filename.c_str()); Serial.setDebugOutput(true);
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; WiFiUDP::stopAll();
if (!Update.begin(maxSketchSpace)) { //start with max available size Serial.printf("Update: %s\n", upload.filename.c_str());
Update.printError(Serial); uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
if (!Update.begin(maxSketchSpace)) { // 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);
} }
} else if (upload.status == UPLOAD_FILE_WRITE) { yield();
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);
}
yield();
});
server.begin(); server.begin();
MDNS.addService("http", "tcp", 80); MDNS.addService("http", "tcp", 80);

View File

@ -41,7 +41,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char *ssid = STASSID; const char *ssid = STASSID;
@ -72,9 +72,7 @@ void setClock() {
// Try and connect using a WiFiClientBearSSL to specified host:port and dump URL // Try and connect using a WiFiClientBearSSL to specified host:port and dump URL
void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_t port, const char *path) { void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_t port, const char *path) {
if (!path) { if (!path) { path = "/"; }
path = "/";
}
Serial.printf("Trying: %s:443...", host); Serial.printf("Trying: %s:443...", host);
client->connect(host, port); client->connect(host, port);
@ -94,11 +92,9 @@ void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_
do { do {
char tmp[32]; char tmp[32];
memset(tmp, 0, 32); memset(tmp, 0, 32);
int rlen = client->read((uint8_t*)tmp, sizeof(tmp) - 1); int rlen = client->read((uint8_t *)tmp, sizeof(tmp) - 1);
yield(); yield();
if (rlen < 0) { if (rlen < 0) { break; }
break;
}
// Only print out first line up to \r, then abort connection // Only print out first line up to \r, then abort connection
char *nl = strchr(tmp, '\r'); char *nl = strchr(tmp, '\r');
if (nl) { if (nl) {
@ -136,13 +132,13 @@ void setup() {
Serial.println("IP address: "); Serial.println("IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
setClock(); // Required for X.509 validation setClock(); // Required for X.509 validation
int numCerts = certStore.initCertStore(LittleFS, PSTR("/certs.idx"), PSTR("/certs.ar")); int numCerts = certStore.initCertStore(LittleFS, PSTR("/certs.idx"), PSTR("/certs.ar"));
Serial.printf("Number of CA certs read: %d\n", numCerts); Serial.printf("Number of CA certs read: %d\n", numCerts);
if (numCerts == 0) { if (numCerts == 0) {
Serial.printf("No certs found. Did you run certs-from-mozilla.py and upload the LittleFS directory before running?\n"); Serial.printf("No certs found. Did you run certs-from-mozilla.py and upload the LittleFS directory before running?\n");
return; // Can't connect to anything w/o certs! return; // Can't connect to anything w/o certs!
} }
BearSSL::WiFiClientSecure *bear = new BearSSL::WiFiClientSecure(); BearSSL::WiFiClientSecure *bear = new BearSSL::WiFiClientSecure();
@ -156,9 +152,7 @@ void setup() {
void loop() { void loop() {
Serial.printf("\nPlease enter a website address (www.blah.com) to connect to: "); Serial.printf("\nPlease enter a website address (www.blah.com) to connect to: ");
String site; String site;
do { do { site = Serial.readString(); } while (site == "");
site = Serial.readString();
} while (site == "");
// Strip newline if present // Strip newline if present
site.replace(String("\r"), emptyString); site.replace(String("\r"), emptyString);
site.replace(String("\n"), emptyString); site.replace(String("\n"), emptyString);
@ -170,4 +164,3 @@ void loop() {
fetchURL(bear, site.c_str(), 443, "/"); fetchURL(bear, site.c_str(), 443, "/");
delete bear; delete bear;
} }

View File

@ -9,7 +9,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char *ssid = STASSID; const char *ssid = STASSID;
@ -22,13 +22,11 @@ void fetch(BearSSL::WiFiClientSecure *client) {
oneShot timeout(5000); oneShot timeout(5000);
do { do {
char tmp[32]; char tmp[32];
int rlen = client->read((uint8_t*)tmp, sizeof(tmp) - 1); int rlen = client->read((uint8_t *)tmp, sizeof(tmp) - 1);
yield(); yield();
if (rlen < 0) { if (rlen < 0) { break; }
break;
}
if (rlen == 0) { if (rlen == 0) {
delay(10); // Give background processes some time delay(10); // Give background processes some time
continue; continue;
} }
tmp[rlen] = '\0'; tmp[rlen] = '\0';
@ -82,9 +80,7 @@ int fetchMaxFragmentLength() {
bool mfln = client.probeMaxFragmentLength("tls.mbed.org", 443, 512); bool mfln = client.probeMaxFragmentLength("tls.mbed.org", 443, 512);
Serial.printf("\nConnecting to https://tls.mbed.org\n"); Serial.printf("\nConnecting to https://tls.mbed.org\n");
Serial.printf("MFLN supported: %s\n", mfln ? "yes" : "no"); Serial.printf("MFLN supported: %s\n", mfln ? "yes" : "no");
if (mfln) { if (mfln) { client.setBufferSizes(512, 512); }
client.setBufferSizes(512, 512);
}
client.connect("tls.mbed.org", 443); client.connect("tls.mbed.org", 443);
if (client.connected()) { if (client.connected()) {
Serial.printf("MFLN status: %s\n", client.getMFLNStatus() ? "true" : "false"); Serial.printf("MFLN status: %s\n", client.getMFLNStatus() ? "true" : "false");

View File

@ -39,7 +39,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char *ssid = STASSID; const char *ssid = STASSID;
@ -138,11 +138,11 @@ GBEnkz4KpKv7TkHoW+j7F5EMcLcSrUIpyw==
#endif #endif
#define CACHE_SIZE 5 // Number of sessions to cache. #define CACHE_SIZE 5 // Number of sessions to cache.
#define USE_CACHE // Enable SSL session caching. #define USE_CACHE // Enable SSL session caching.
// Caching SSL sessions shortens the length of the SSL handshake. // Caching SSL sessions shortens the length of the SSL handshake.
// You can see the performance improvement by looking at the // You can see the performance improvement by looking at the
// Network tab of the developer tools of your browser. // Network tab of the developer tools of your browser.
//#define DYNAMIC_CACHE // Whether to dynamically allocate the cache. //#define DYNAMIC_CACHE // Whether to dynamically allocate the cache.
#if defined(USE_CACHE) && defined(DYNAMIC_CACHE) #if defined(USE_CACHE) && defined(DYNAMIC_CACHE)
@ -181,7 +181,7 @@ void setup() {
#ifndef USE_EC #ifndef USE_EC
server.setRSACert(serverCertList, serverPrivKey); server.setRSACert(serverCertList, serverPrivKey);
#else #else
server.setECCert(serverCertList, BR_KEYTYPE_KEYX|BR_KEYTYPE_SIGN, serverPrivKey); server.setECCert(serverCertList, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, serverPrivKey);
#endif #endif
// Set the server's cache // Set the server's cache
@ -193,31 +193,28 @@ void setup() {
server.begin(); server.begin();
} }
static const char *HTTP_RES = static const char *HTTP_RES = "HTTP/1.0 200 OK\r\n"
"HTTP/1.0 200 OK\r\n" "Connection: close\r\n"
"Connection: close\r\n" "Content-Length: 62\r\n"
"Content-Length: 62\r\n" "Content-Type: text/html; charset=iso-8859-1\r\n"
"Content-Type: text/html; charset=iso-8859-1\r\n" "\r\n"
"\r\n" "<html>\r\n"
"<html>\r\n" "<body>\r\n"
"<body>\r\n" "<p>Hello from ESP8266!</p>\r\n"
"<p>Hello from ESP8266!</p>\r\n" "</body>\r\n"
"</body>\r\n" "</html>\r\n";
"</html>\r\n";
void loop() { void loop() {
static int cnt; static int cnt;
BearSSL::WiFiClientSecure incoming = server.accept(); BearSSL::WiFiClientSecure incoming = server.accept();
if (!incoming) { if (!incoming) { return; }
return; Serial.printf("Incoming connection...%d\n", cnt++);
}
Serial.printf("Incoming connection...%d\n",cnt++);
// Ugly way to wait for \r\n (i.e. end of HTTP request which we don't actually parse here) // Ugly way to wait for \r\n (i.e. end of HTTP request which we don't actually parse here)
uint32_t timeout=millis() + 1000; uint32_t timeout = millis() + 1000;
int lcwn = 0; int lcwn = 0;
for (;;) { for (;;) {
unsigned char x=0; unsigned char x = 0;
if ((millis() > timeout) || (incoming.available() && incoming.read(&x, 1) < 0)) { if ((millis() > timeout) || (incoming.available() && incoming.read(&x, 1) < 0)) {
incoming.stop(); incoming.stop();
Serial.printf("Connection error, closed\n"); Serial.printf("Connection error, closed\n");
@ -228,14 +225,12 @@ void loop() {
} else if (x == 0x0D) { } else if (x == 0x0D) {
continue; continue;
} else if (x == 0x0A) { } else if (x == 0x0A) {
if (lcwn) { if (lcwn) { break; }
break;
}
lcwn = 1; lcwn = 1;
} else } else
lcwn = 0; lcwn = 0;
} }
incoming.write((uint8_t*)HTTP_RES, strlen(HTTP_RES)); incoming.write((uint8_t *)HTTP_RES, strlen(HTTP_RES));
incoming.flush(); incoming.flush();
incoming.stop(); incoming.stop();
Serial.printf("Connection closed.\n"); Serial.printf("Connection closed.\n");

View File

@ -67,7 +67,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char *ssid = STASSID; const char *ssid = STASSID;
@ -160,8 +160,7 @@ seoK24dHmt6tWmn/sbxX7Aa6TL/4mVlFoOgcaTJyVaY/BrY=
// head of the app. // head of the app.
// Set time via NTP, as required for x.509 validation // Set time via NTP, as required for x.509 validation
void setClock() void setClock() {
{
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov"); configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
Serial.print("Waiting for NTP time sync: "); Serial.print("Waiting for NTP time sync: ");
@ -199,7 +198,7 @@ void setup() {
Serial.println("IP address: "); Serial.println("IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
setClock(); // Required for X.509 validation setClock(); // Required for X.509 validation
// Attach the server private cert/key combo // Attach the server private cert/key combo
BearSSL::X509List *serverCertList = new BearSSL::X509List(server_cert); BearSSL::X509List *serverCertList = new BearSSL::X509List(server_cert);
@ -214,30 +213,27 @@ void setup() {
server.begin(); server.begin();
} }
static const char *HTTP_RES = static const char *HTTP_RES = "HTTP/1.0 200 OK\r\n"
"HTTP/1.0 200 OK\r\n" "Connection: close\r\n"
"Connection: close\r\n" "Content-Length: 59\r\n"
"Content-Length: 59\r\n" "Content-Type: text/html; charset=iso-8859-1\r\n"
"Content-Type: text/html; charset=iso-8859-1\r\n" "\r\n"
"\r\n" "<html>\r\n"
"<html>\r\n" "<body>\r\n"
"<body>\r\n" "<p>Hello my friend!</p>\r\n"
"<p>Hello my friend!</p>\r\n" "</body>\r\n"
"</body>\r\n" "</html>\r\n";
"</html>\r\n";
void loop() { void loop() {
BearSSL::WiFiClientSecure incoming = server.accept(); BearSSL::WiFiClientSecure incoming = server.accept();
if (!incoming) { if (!incoming) { return; }
return;
}
Serial.println("Incoming connection...\n"); Serial.println("Incoming connection...\n");
// Ugly way to wait for \r\n (i.e. end of HTTP request which we don't actually parse here) // Ugly way to wait for \r\n (i.e. end of HTTP request which we don't actually parse here)
uint32_t timeout=millis() + 1000; uint32_t timeout = millis() + 1000;
int lcwn = 0; int lcwn = 0;
for (;;) { for (;;) {
unsigned char x=0; unsigned char x = 0;
if ((millis() > timeout) || (incoming.available() && incoming.read(&x, 1) < 0)) { if ((millis() > timeout) || (incoming.available() && incoming.read(&x, 1) < 0)) {
incoming.stop(); incoming.stop();
Serial.printf("Connection error, closed\n"); Serial.printf("Connection error, closed\n");
@ -248,14 +244,12 @@ void loop() {
} else if (x == 0x0D) { } else if (x == 0x0D) {
continue; continue;
} else if (x == 0x0A) { } else if (x == 0x0A) {
if (lcwn) { if (lcwn) { break; }
break;
}
lcwn = 1; lcwn = 1;
} else } else
lcwn = 0; lcwn = 0;
} }
incoming.write((uint8_t*)HTTP_RES, strlen(HTTP_RES)); incoming.write((uint8_t *)HTTP_RES, strlen(HTTP_RES));
incoming.flush(); incoming.flush();
incoming.stop(); incoming.stop();
Serial.printf("Connection closed.\n"); Serial.printf("Connection closed.\n");

View File

@ -9,13 +9,13 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char *ssid = STASSID; const char *ssid = STASSID;
const char *pass = STAPSK; const char *pass = STAPSK;
const char * path = "/"; const char *path = "/";
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
@ -53,9 +53,7 @@ void setup() {
// Try and connect using a WiFiClientBearSSL to specified host:port and dump HTTP response // Try and connect using a WiFiClientBearSSL to specified host:port and dump HTTP response
void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_t port, const char *path) { void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_t port, const char *path) {
if (!path) { if (!path) { path = "/"; }
path = "/";
}
Serial.printf("Trying: %s:443...", host); Serial.printf("Trying: %s:443...", host);
client->connect(host, port); client->connect(host, port);
@ -75,11 +73,9 @@ void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_
do { do {
char tmp[32]; char tmp[32];
memset(tmp, 0, 32); memset(tmp, 0, 32);
int rlen = client->read((uint8_t*)tmp, sizeof(tmp) - 1); int rlen = client->read((uint8_t *)tmp, sizeof(tmp) - 1);
yield(); yield();
if (rlen < 0) { if (rlen < 0) { break; }
break;
}
// Only print out first line up to \r, then abort connection // Only print out first line up to \r, then abort connection
char *nl = strchr(tmp, '\r'); char *nl = strchr(tmp, '\r');
if (nl) { if (nl) {
@ -130,6 +126,5 @@ void loop() {
finish = millis(); finish = millis();
Serial.printf("Total time: %dms\n", finish - start); Serial.printf("Total time: %dms\n", finish - start);
delay(10000); // Avoid DDOSing github delay(10000); // Avoid DDOSing github
} }

View File

@ -12,13 +12,13 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char *ssid = STASSID; const char *ssid = STASSID;
const char *pass = STAPSK; const char *pass = STAPSK;
const char * path = "/"; const char *path = "/";
// Set time via NTP, as required for x.509 validation // Set time via NTP, as required for x.509 validation
void setClock() { void setClock() {
@ -40,9 +40,7 @@ void setClock() {
// Try and connect using a WiFiClientBearSSL to specified host:port and dump HTTP response // Try and connect using a WiFiClientBearSSL to specified host:port and dump HTTP response
void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_t port, const char *path) { void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_t port, const char *path) {
if (!path) { if (!path) { path = "/"; }
path = "/";
}
ESP.resetFreeContStack(); ESP.resetFreeContStack();
uint32_t freeStackStart = ESP.getFreeContStack(); uint32_t freeStackStart = ESP.getFreeContStack();
@ -64,11 +62,9 @@ void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_
do { do {
char tmp[32]; char tmp[32];
memset(tmp, 0, 32); memset(tmp, 0, 32);
int rlen = client->read((uint8_t*)tmp, sizeof(tmp) - 1); int rlen = client->read((uint8_t *)tmp, sizeof(tmp) - 1);
yield(); yield();
if (rlen < 0) { if (rlen < 0) { break; }
break;
}
// Only print out first line up to \r, then abort connection // Only print out first line up to \r, then abort connection
char *nl = strchr(tmp, '\r'); char *nl = strchr(tmp, '\r');
if (nl) { if (nl) {

View File

@ -17,7 +17,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
@ -74,10 +74,7 @@ void setup() {
Serial.print("Requesting URL: "); Serial.print("Requesting URL: ");
Serial.println(url); Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.1\r\n" + client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + github_host + "\r\n" + "User-Agent: BuildFailureDetectorESP8266\r\n" + "Connection: close\r\n\r\n");
"Host: " + github_host + "\r\n" +
"User-Agent: BuildFailureDetectorESP8266\r\n" +
"Connection: close\r\n\r\n");
Serial.println("Request sent"); Serial.println("Request sent");
while (client.connected()) { while (client.connected()) {
@ -100,5 +97,4 @@ void setup() {
Serial.println("Closing connection"); Serial.println("Closing connection");
} }
void loop() { void loop() {}
}

View File

@ -23,12 +23,12 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
#define FQDN F("www.google.com") // with both IPv4 & IPv6 addresses #define FQDN F("www.google.com") // with both IPv4 & IPv6 addresses
#define FQDN2 F("www.yahoo.com") // with both IPv4 & IPv6 addresses #define FQDN2 F("www.yahoo.com") // with both IPv4 & IPv6 addresses
#define FQDN6 F("ipv6.google.com") // does not resolve in IPv4 #define FQDN6 F("ipv6.google.com") // does not resolve in IPv4
#define STATUSDELAY_MS 10000 #define STATUSDELAY_MS 10000
#define TCP_PORT 23 #define TCP_PORT 23
#define UDP_PORT 23 #define UDP_PORT 23
@ -71,29 +71,17 @@ void status(Print& out) {
for (int i = 0; i < DNS_MAX_SERVERS; i++) { for (int i = 0; i < DNS_MAX_SERVERS; i++) {
IPAddress dns = WiFi.dnsIP(i); IPAddress dns = WiFi.dnsIP(i);
if (dns.isSet()) { if (dns.isSet()) { out.printf("dns%d: %s\n", i, dns.toString().c_str()); }
out.printf("dns%d: %s\n", i, dns.toString().c_str());
}
} }
out.println(F("Try me at these addresses:")); out.println(F("Try me at these addresses:"));
out.println(F("(with 'telnet <addr> or 'nc -u <addr> 23')")); out.println(F("(with 'telnet <addr> or 'nc -u <addr> 23')"));
for (auto a : addrList) { for (auto a : addrList) {
out.printf("IF='%s' IPv6=%d local=%d hostname='%s' addr= %s", out.printf("IF='%s' IPv6=%d local=%d hostname='%s' addr= %s", a.ifname().c_str(), a.isV6(), a.isLocal(), a.ifhostname(), a.toString().c_str());
a.ifname().c_str(),
a.isV6(),
a.isLocal(),
a.ifhostname(),
a.toString().c_str());
if (a.isLegacy()) { if (a.isLegacy()) { out.printf(" / mask:%s / gw:%s", a.netmask().toString().c_str(), a.gw().toString().c_str()); }
out.printf(" / mask:%s / gw:%s",
a.netmask().toString().c_str(),
a.gw().toString().c_str());
}
out.println(); out.println();
} }
// lwIP's dns client will ask for IPv4 first (by default) // lwIP's dns client will ask for IPv4 first (by default)
@ -101,8 +89,8 @@ void status(Print& out) {
fqdn(out, FQDN); fqdn(out, FQDN);
fqdn(out, FQDN6); fqdn(out, FQDN6);
#if LWIP_IPV4 && LWIP_IPV6 #if LWIP_IPV4 && LWIP_IPV6
fqdn_rt(out, FQDN, DNSResolveType::DNS_AddrType_IPv4_IPv6); // IPv4 before IPv6 fqdn_rt(out, FQDN, DNSResolveType::DNS_AddrType_IPv4_IPv6); // IPv4 before IPv6
fqdn_rt(out, FQDN2, DNSResolveType::DNS_AddrType_IPv6_IPv4); // IPv6 before IPv4 fqdn_rt(out, FQDN2, DNSResolveType::DNS_AddrType_IPv6_IPv4); // IPv6 before IPv4
#endif #endif
out.println(F("------------------------------")); out.println(F("------------------------------"));
} }
@ -125,7 +113,7 @@ void setup() {
status(Serial); status(Serial);
#if 0 // 0: legacy connecting loop - 1: wait for IPv6 #if 0 // 0: legacy connecting loop - 1: wait for IPv6
// legacy loop (still valid with IPv4 only) // legacy loop (still valid with IPv4 only)
@ -146,11 +134,9 @@ void setup() {
for (bool configured = false; !configured;) { for (bool configured = false; !configured;) {
for (auto addr : addrList) for (auto addr : addrList)
if ((configured = !addr.isLocal() if ((configured = !addr.isLocal()
// && addr.isV6() // uncomment when IPv6 is mandatory // && addr.isV6() // uncomment when IPv6 is mandatory
// && addr.ifnumber() == STATION_IF // && addr.ifnumber() == STATION_IF
)) { )) { break; }
break;
}
Serial.print('.'); Serial.print('.');
delay(500); delay(500);
} }
@ -188,10 +174,8 @@ void loop() {
udp.remoteIP().printTo(Serial); udp.remoteIP().printTo(Serial);
Serial.print(F(" :")); Serial.print(F(" :"));
Serial.println(udp.remotePort()); Serial.println(udp.remotePort());
int c; int c;
while ((c = udp.read()) >= 0) { while ((c = udp.read()) >= 0) { Serial.write(c); }
Serial.write(c);
}
// send a reply, to the IP address and port that sent us the packet we received // send a reply, to the IP address and port that sent us the packet we received
udp.beginPacket(udp.remoteIP(), udp.remotePort()); udp.beginPacket(udp.remoteIP(), udp.remotePort());
@ -200,8 +184,5 @@ void loop() {
} }
if (showStatusOnSerialNow) { if (showStatusOnSerialNow) { status(Serial); }
status(Serial);
}
} }

View File

@ -23,24 +23,24 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char * ssid = STASSID; // your network SSID (name) const char* ssid = STASSID; // your network SSID (name)
const char * pass = STAPSK; // your network password const char* pass = STAPSK; // your network password
unsigned int localPort = 2390; // local port to listen for UDP packets unsigned int localPort = 2390; // local port to listen for UDP packets
/* Don't hardwire the IP address or we won't get the benefits of the pool. /* Don't hardwire the IP address or we won't get the benefits of the pool.
Lookup the IP address for the host name instead */ Lookup the IP address for the host name instead */
//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server // IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
IPAddress timeServerIP; // time.nist.gov NTP server address IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov"; const char* ntpServerName = "time.nist.gov";
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets
// A UDP instance to let us send and receive packets over UDP // A UDP instance to let us send and receive packets over UDP
WiFiUDP udp; WiFiUDP udp;
@ -73,10 +73,10 @@ void setup() {
} }
void loop() { void loop() {
//get a random server from the pool // get a random server from the pool
WiFi.hostByName(ntpServerName, timeServerIP); WiFi.hostByName(ntpServerName, timeServerIP);
sendNTPpacket(timeServerIP); // send an NTP packet to a time server sendNTPpacket(timeServerIP); // send an NTP packet to a time server
// wait to see if a reply is available // wait to see if a reply is available
delay(1000); delay(1000);
@ -87,10 +87,10 @@ void loop() {
Serial.print("packet received, length="); Serial.print("packet received, length=");
Serial.println(cb); Serial.println(cb);
// We've received a packet, read the data from it // We've received a packet, read the data from it
udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
//the timestamp starts at byte 40 of the received packet and is four bytes, // the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words: // or two words, long. First, esxtract the two words:
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
@ -112,19 +112,19 @@ void loop() {
// print the hour, minute and second: // print the hour, minute and second:
Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day)
Serial.print(':'); Serial.print(':');
if (((epoch % 3600) / 60) < 10) { if (((epoch % 3600) / 60) < 10) {
// In the first 10 minutes of each hour, we'll want a leading '0' // In the first 10 minutes of each hour, we'll want a leading '0'
Serial.print('0'); Serial.print('0');
} }
Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute)
Serial.print(':'); Serial.print(':');
if ((epoch % 60) < 10) { if ((epoch % 60) < 10) {
// In the first 10 seconds of each minute, we'll want a leading '0' // In the first 10 seconds of each minute, we'll want a leading '0'
Serial.print('0'); Serial.print('0');
} }
Serial.println(epoch % 60); // print the second Serial.println(epoch % 60); // print the second
} }
// wait ten seconds before asking for the time again // wait ten seconds before asking for the time again
delay(10000); delay(10000);
@ -137,19 +137,19 @@ void sendNTPpacket(IPAddress& address) {
memset(packetBuffer, 0, NTP_PACKET_SIZE); memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request // Initialize values needed to form NTP request
// (see URL above for details on the packets) // (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion // 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49; packetBuffer[12] = 49;
packetBuffer[13] = 0x4E; packetBuffer[13] = 0x4E;
packetBuffer[14] = 49; packetBuffer[14] = 49;
packetBuffer[15] = 52; packetBuffer[15] = 52;
// all NTP fields have been given values, now // all NTP fields have been given values, now
// you can send a packet requesting a timestamp: // you can send a packet requesting a timestamp:
udp.beginPacket(address, 123); //NTP requests are to port 123 udp.beginPacket(address, 123); // NTP requests are to port 123
udp.write(packetBuffer, NTP_PACKET_SIZE); udp.write(packetBuffer, NTP_PACKET_SIZE);
udp.endPacket(); udp.endPacket();
} }

View File

@ -25,10 +25,10 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
const char* password = STAPSK; const char* password = STAPSK;
ArduinoWiFiServer server(2323); ArduinoWiFiServer server(2323);
@ -60,13 +60,13 @@ void setup() {
void loop() { void loop() {
WiFiClient client = server.available(); // returns first client which has data to read or a 'false' client WiFiClient client = server.available(); // returns first client which has data to read or a 'false' client
if (client) { // client is true only if it is connected and has data to read if (client) { // client is true only if it is connected and has data to read
String s = client.readStringUntil('\n'); // read the message incoming from one of the clients String s = client.readStringUntil('\n'); // read the message incoming from one of the clients
s.trim(); // trim eventual \r s.trim(); // trim eventual \r
Serial.println(s); // print the message to Serial Monitor Serial.println(s); // print the message to Serial Monitor
client.print("echo: "); // this is only for the sending client client.print("echo: "); // this is only for the sending client
server.println(s); // send the message to all connected clients server.println(s); // send the message to all connected clients
server.flush(); // flush the buffers server.flush(); // flush the buffers
} }
} }

View File

@ -7,7 +7,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "mynetwork" #define STASSID "mynetwork"
#define STAPSK "mynetworkpassword" #define STAPSK "mynetworkpassword"
#endif #endif
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
@ -30,7 +30,7 @@ void dump(int netif_idx, const char* data, size_t len, int out, int success) {
// optional filter example: if (netDump_is_ARP(data)) // optional filter example: if (netDump_is_ARP(data))
{ {
netDump(Serial, data, len); netDump(Serial, data, len);
//netDumpHex(Serial, data, len); // netDumpHex(Serial, data, len);
} }
} }
#endif #endif
@ -51,19 +51,14 @@ void setup() {
Serial.print('.'); Serial.print('.');
delay(500); delay(500);
} }
Serial.printf("\nSTA: %s (dns: %s / %s)\n", Serial.printf("\nSTA: %s (dns: %s / %s)\n", WiFi.localIP().toString().c_str(), WiFi.dnsIP(0).toString().c_str(), WiFi.dnsIP(1).toString().c_str());
WiFi.localIP().toString().c_str(),
WiFi.dnsIP(0).toString().c_str(),
WiFi.dnsIP(1).toString().c_str());
// give DNS servers to AP side // give DNS servers to AP side
dhcpSoftAP.dhcps_set_dns(0, WiFi.dnsIP(0)); dhcpSoftAP.dhcps_set_dns(0, WiFi.dnsIP(0));
dhcpSoftAP.dhcps_set_dns(1, WiFi.dnsIP(1)); dhcpSoftAP.dhcps_set_dns(1, WiFi.dnsIP(1));
WiFi.softAPConfig( // enable AP, with android-compatible google domain WiFi.softAPConfig( // enable AP, with android-compatible google domain
IPAddress(172, 217, 28, 254), IPAddress(172, 217, 28, 254), IPAddress(172, 217, 28, 254), IPAddress(255, 255, 255, 0));
IPAddress(172, 217, 28, 254),
IPAddress(255, 255, 255, 0));
WiFi.softAP(STASSID "extender", STAPSK); WiFi.softAP(STASSID "extender", STAPSK);
Serial.printf("AP: %s\n", WiFi.softAPIP().toString().c_str()); Serial.printf("AP: %s\n", WiFi.softAPIP().toString().c_str());
@ -73,14 +68,10 @@ void setup() {
if (ret == ERR_OK) { if (ret == ERR_OK) {
ret = ip_napt_enable_no(SOFTAP_IF, 1); ret = ip_napt_enable_no(SOFTAP_IF, 1);
Serial.printf("ip_napt_enable_no(SOFTAP_IF): ret=%d (OK=%d)\n", (int)ret, (int)ERR_OK); Serial.printf("ip_napt_enable_no(SOFTAP_IF): ret=%d (OK=%d)\n", (int)ret, (int)ERR_OK);
if (ret == ERR_OK) { if (ret == ERR_OK) { Serial.printf("WiFi Network '%s' with same password is now NATed behind '%s'\n", STASSID "extender", STASSID); }
Serial.printf("WiFi Network '%s' with same password is now NATed behind '%s'\n", STASSID "extender", STASSID);
}
} }
Serial.printf("Heap after napt init: %d\n", ESP.getFreeHeap()); Serial.printf("Heap after napt init: %d\n", ESP.getFreeHeap());
if (ret != ERR_OK) { if (ret != ERR_OK) { Serial.printf("NAPT initialization failed\n"); }
Serial.printf("NAPT initialization failed\n");
}
} }
#else #else
@ -92,6 +83,4 @@ void setup() {
#endif #endif
void loop() { void loop() {}
}

View File

@ -20,14 +20,14 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
unsigned int localPort = 8888; // local port to listen on unsigned int localPort = 8888; // local port to listen on
// buffers for receiving and sending data // buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1]; //buffer to hold incoming packet, char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1]; // buffer to hold incoming packet,
char ReplyBuffer[] = "acknowledged\r\n"; // a string to send back char ReplyBuffer[] = "acknowledged\r\n"; // a string to send back
WiFiUDP Udp; WiFiUDP Udp;
@ -49,11 +49,7 @@ void loop() {
// if there's data available, read a packet // if there's data available, read a packet
int packetSize = Udp.parsePacket(); int packetSize = Udp.parsePacket();
if (packetSize) { if (packetSize) {
Serial.printf("Received packet of size %d from %s:%d\n (to %s:%d, free heap = %d B)\n", Serial.printf("Received packet of size %d from %s:%d\n (to %s:%d, free heap = %d B)\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort(), Udp.destinationIP().toString().c_str(), Udp.localPort(), ESP.getFreeHeap());
packetSize,
Udp.remoteIP().toString().c_str(), Udp.remotePort(),
Udp.destinationIP().toString().c_str(), Udp.localPort(),
ESP.getFreeHeap());
// read the packet into packetBufffer // read the packet into packetBufffer
int n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); int n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
@ -66,11 +62,10 @@ void loop() {
Udp.write(ReplyBuffer); Udp.write(ReplyBuffer);
Udp.endPacket(); Udp.endPacket();
} }
} }
/* /*
test (shell/netcat): test (shell/netcat):
-------------------- --------------------
nc -u 192.168.esp.address 8888 nc -u 192.168.esp.address 8888
*/ */

View File

@ -36,7 +36,7 @@
#ifndef APSSID #ifndef APSSID
#define APSSID "ESPap" #define APSSID "ESPap"
#define APPSK "thereisnospoon" #define APPSK "thereisnospoon"
#endif #endif
/* Set these to your desired credentials. */ /* Set these to your desired credentials. */

View File

@ -7,10 +7,10 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
const char* password = STAPSK; const char* password = STAPSK;
const char* host = "djxmmx.net"; const char* host = "djxmmx.net";
@ -61,9 +61,7 @@ void loop() {
// This will send a string to the server // This will send a string to the server
Serial.println("sending data to server"); Serial.println("sending data to server");
if (client.connected()) { if (client.connected()) { client.println("hello from ESP8266"); }
client.println("hello from ESP8266");
}
// wait for data to be available // wait for data to be available
unsigned long timeout = millis(); unsigned long timeout = millis();
@ -90,7 +88,7 @@ void loop() {
client.stop(); client.stop();
if (wait) { if (wait) {
delay(300000); // execute once every 5 minutes, don't flood remote service delay(300000); // execute once every 5 minutes, don't flood remote service
} }
wait = true; wait = true;
} }

View File

@ -9,10 +9,10 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
const char* password = STAPSK; const char* password = STAPSK;
const char* host = "192.168.1.1"; const char* host = "192.168.1.1";
@ -64,7 +64,7 @@ void loop() {
// This will send the request to the server // This will send the request to the server
client.println("hello from ESP8266"); client.println("hello from ESP8266");
//read back one line from server // read back one line from server
Serial.println("receiving from remote server"); Serial.println("receiving from remote server");
String line = client.readStringUntil('\r'); String line = client.readStringUntil('\r');
Serial.println(line); Serial.println(line);
@ -75,4 +75,3 @@ void loop() {
Serial.println("wait 5 sec..."); Serial.println("wait 5 sec...");
delay(5000); delay(5000);
} }

View File

@ -7,11 +7,11 @@
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <ESP8266mDNS.h> #include <ESP8266mDNS.h>
#include <PolledTimeout.h> #include <PolledTimeout.h>
#include <algorithm> // std::min #include <algorithm> // std::min
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
constexpr int port = 23; constexpr int port = 23;
@ -19,12 +19,12 @@ constexpr int port = 23;
WiFiServer server(port); WiFiServer server(port);
WiFiClient client; WiFiClient client;
constexpr size_t sizes [] = { 0, 512, 384, 256, 128, 64, 16, 8, 4 }; constexpr size_t sizes[] = { 0, 512, 384, 256, 128, 64, 16, 8, 4 };
constexpr uint32_t breathMs = 200; constexpr uint32_t breathMs = 200;
esp8266::polledTimeout::oneShotFastMs enoughMs(breathMs); esp8266::polledTimeout::oneShotFastMs enoughMs(breathMs);
esp8266::polledTimeout::periodicFastMs test(2000); esp8266::polledTimeout::periodicFastMs test(2000);
int t = 1; // test (1, 2 or 3, see below) int t = 1; // test (1, 2 or 3, see below)
int s = 0; // sizes[] index int s = 0; // sizes[] index
void setup() { void setup() {
@ -63,19 +63,13 @@ void loop() {
static uint32_t cnt = 0; static uint32_t cnt = 0;
if (test && cnt) { if (test && cnt) {
Serial.printf("measured-block-size=%u min-free-stack=%u", tot / cnt, ESP.getFreeContStack()); Serial.printf("measured-block-size=%u min-free-stack=%u", tot / cnt, ESP.getFreeContStack());
if (t == 2 && sizes[s]) { if (t == 2 && sizes[s]) { Serial.printf(" (blocks: at most %d bytes)", sizes[s]); }
Serial.printf(" (blocks: at most %d bytes)", sizes[s]); if (t == 3 && sizes[s]) { Serial.printf(" (blocks: exactly %d bytes)", sizes[s]); }
} if (t == 3 && !sizes[s]) { Serial.printf(" (blocks: any size)"); }
if (t == 3 && sizes[s]) {
Serial.printf(" (blocks: exactly %d bytes)", sizes[s]);
}
if (t == 3 && !sizes[s]) {
Serial.printf(" (blocks: any size)");
}
Serial.printf("\n"); Serial.printf("\n");
} }
//check if there are any new clients // check if there are any new clients
if (server.hasClient()) { if (server.hasClient()) {
client = server.accept(); client = server.accept();
Serial.println("New client"); Serial.println("New client");
@ -84,10 +78,25 @@ void loop() {
if (Serial.available()) { if (Serial.available()) {
s = (s + 1) % (sizeof(sizes) / sizeof(sizes[0])); s = (s + 1) % (sizeof(sizes) / sizeof(sizes[0]));
switch (Serial.read()) { switch (Serial.read()) {
case '1': if (t != 1) s = 0; t = 1; Serial.println("byte-by-byte (watch then press 2, 3 or 4)"); break; case '1':
case '2': if (t != 2) s = 1; t = 2; Serial.printf("through buffer (watch then press 2 again, or 1, 3 or 4)\n"); break; if (t != 1) s = 0;
case '3': if (t != 3) s = 0; t = 3; Serial.printf("direct access (sendAvailable - watch then press 3 again, or 1, 2 or 4)\n"); break; t = 1;
case '4': t = 4; Serial.printf("direct access (sendAll - close peer to stop, then press 1, 2 or 3 before restarting peer)\n"); break; Serial.println("byte-by-byte (watch then press 2, 3 or 4)");
break;
case '2':
if (t != 2) s = 1;
t = 2;
Serial.printf("through buffer (watch then press 2 again, or 1, 3 or 4)\n");
break;
case '3':
if (t != 3) s = 0;
t = 3;
Serial.printf("direct access (sendAvailable - watch then press 3 again, or 1, 2 or 4)\n");
break;
case '4':
t = 4;
Serial.printf("direct access (sendAll - close peer to stop, then press 1, 2 or 3 before restarting peer)\n");
break;
} }
tot = cnt = 0; tot = cnt = 0;
ESP.resetFreeContStack(); ESP.resetFreeContStack();
@ -113,9 +122,7 @@ void loop() {
uint8_t buf[maxTo]; uint8_t buf[maxTo];
size_t tcp_got = client.read(buf, maxTo); size_t tcp_got = client.read(buf, maxTo);
size_t tcp_sent = client.write(buf, tcp_got); size_t tcp_sent = client.write(buf, tcp_got);
if (tcp_sent != maxTo) { if (tcp_sent != maxTo) { Serial.printf("len mismatch: available:%zd tcp-read:%zd serial-write:%zd\n", maxTo, tcp_got, tcp_sent); }
Serial.printf("len mismatch: available:%zd tcp-read:%zd serial-write:%zd\n", maxTo, tcp_got, tcp_sent);
}
tot += tcp_sent; tot += tcp_sent;
cnt++; cnt++;
} }
@ -141,7 +148,7 @@ void loop() {
else if (t == 4) { else if (t == 4) {
// stream to print, possibly with only one copy // stream to print, possibly with only one copy
tot += client.sendAll(&client); // this one might not exit until peer close tot += client.sendAll(&client); // this one might not exit until peer close
cnt++; cnt++;
switch (client.getLastSendReport()) { switch (client.getLastSendReport()) {
@ -152,5 +159,4 @@ void loop() {
case Stream::Report::ShortOperation: Serial.println("Stream::send: short transfer"); break; case Stream::Report::ShortOperation: Serial.println("Stream::send: short transfer"); break;
} }
} }
} }

View File

@ -18,10 +18,10 @@
#ifndef APSSID #ifndef APSSID
#define APSSID "esp8266" #define APSSID "esp8266"
#define APPSK "esp8266" #define APPSK "esp8266"
#endif #endif
const char* ssid = APSSID; const char* ssid = APSSID;
const char* password = APPSK; const char* password = APPSK;
WiFiEventHandler stationConnectedHandler; WiFiEventHandler stationConnectedHandler;
@ -98,7 +98,6 @@ void loop() {
String macToString(const unsigned char* mac) { String macToString(const unsigned char* mac) {
char buf[20]; char buf[20];
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return String(buf); return String(buf);
} }

View File

@ -11,7 +11,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
@ -55,12 +55,10 @@ void setup() {
void loop() { void loop() {
// Check if a client has connected // Check if a client has connected
WiFiClient client = server.accept(); WiFiClient client = server.accept();
if (!client) { if (!client) { return; }
return;
}
Serial.println(F("new client")); Serial.println(F("new client"));
client.setTimeout(5000); // default is 1000 client.setTimeout(5000); // default is 1000
// Read the first line of the request // Read the first line of the request
String req = client.readStringUntil('\r'); String req = client.readStringUntil('\r');

View File

@ -40,15 +40,7 @@ void loop() {
for (int8_t i = 0; i < scanResult; i++) { for (int8_t i = 0; i < scanResult; i++) {
WiFi.getNetworkInfo(i, ssid, encryptionType, rssi, bssid, channel, hidden); WiFi.getNetworkInfo(i, ssid, encryptionType, rssi, bssid, channel, hidden);
Serial.printf(PSTR(" %02d: [CH %02d] [%02X:%02X:%02X:%02X:%02X:%02X] %ddBm %c %c %s\n"), Serial.printf(PSTR(" %02d: [CH %02d] [%02X:%02X:%02X:%02X:%02X:%02X] %ddBm %c %c %s\n"), i, channel, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], rssi, (encryptionType == ENC_TYPE_NONE) ? ' ' : '*', hidden ? 'H' : 'V', ssid.c_str());
i,
channel,
bssid[0], bssid[1], bssid[2],
bssid[3], bssid[4], bssid[5],
rssi,
(encryptionType == ENC_TYPE_NONE) ? ' ' : '*',
hidden ? 'H' : 'V',
ssid.c_str());
yield(); yield();
} }
} else { } else {

View File

@ -17,7 +17,7 @@
#endif #endif
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <include/WiFiState.h> // WiFiState structure details #include <include/WiFiState.h> // WiFiState structure details
WiFiState state; WiFiState state;
@ -26,7 +26,7 @@ const char* password = STAPSK;
void setup() { void setup() {
Serial.begin(74880); Serial.begin(74880);
//Serial.setDebugOutput(true); // If you need debug output // Serial.setDebugOutput(true); // If you need debug output
Serial.println("Trying to resume WiFi connection..."); Serial.println("Trying to resume WiFi connection...");
// May be necessary after deepSleep. Otherwise you may get "error: pll_cal exceeds 2ms!!!" when trying to connect // May be necessary after deepSleep. Otherwise you may get "error: pll_cal exceeds 2ms!!!" when trying to connect
@ -36,17 +36,14 @@ void setup() {
// Here you can do whatever you need to do that doesn't need a WiFi connection. // Here you can do whatever you need to do that doesn't need a WiFi connection.
// --- // ---
ESP.rtcUserMemoryRead(RTC_USER_DATA_SLOT_WIFI_STATE, reinterpret_cast<uint32_t *>(&state), sizeof(state)); ESP.rtcUserMemoryRead(RTC_USER_DATA_SLOT_WIFI_STATE, reinterpret_cast<uint32_t*>(&state), sizeof(state));
unsigned long start = millis(); unsigned long start = millis();
if (!WiFi.resumeFromShutdown(state) if (!WiFi.resumeFromShutdown(state) || (WiFi.waitForConnectResult(10000) != WL_CONNECTED)) {
|| (WiFi.waitForConnectResult(10000) != WL_CONNECTED)) {
Serial.println("Cannot resume WiFi connection, connecting via begin..."); Serial.println("Cannot resume WiFi connection, connecting via begin...");
WiFi.persistent(false); WiFi.persistent(false);
if (!WiFi.mode(WIFI_STA) if (!WiFi.mode(WIFI_STA) || !WiFi.begin(ssid, password) || (WiFi.waitForConnectResult(10000) != WL_CONNECTED)) {
|| !WiFi.begin(ssid, password)
|| (WiFi.waitForConnectResult(10000) != WL_CONNECTED)) {
WiFi.mode(WIFI_OFF); WiFi.mode(WIFI_OFF);
Serial.println("Cannot connect!"); Serial.println("Cannot connect!");
Serial.flush(); Serial.flush();
@ -64,7 +61,7 @@ void setup() {
// --- // ---
WiFi.shutdown(state); WiFi.shutdown(state);
ESP.rtcUserMemoryWrite(RTC_USER_DATA_SLOT_WIFI_STATE, reinterpret_cast<uint32_t *>(&state), sizeof(state)); ESP.rtcUserMemoryWrite(RTC_USER_DATA_SLOT_WIFI_STATE, reinterpret_cast<uint32_t*>(&state), sizeof(state));
// --- // ---
// Here you can do whatever you need to do that doesn't need a WiFi connection anymore. // Here you can do whatever you need to do that doesn't need a WiFi connection anymore.

View File

@ -20,11 +20,11 @@
*/ */
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <algorithm> // std::min #include <algorithm> // std::min
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
/* /*
@ -64,9 +64,9 @@ SoftwareSerial* logger = nullptr;
#define logger (&Serial1) #define logger (&Serial1)
#endif #endif
#define STACK_PROTECTOR 512 // bytes #define STACK_PROTECTOR 512 // bytes
//how many clients should be able to telnet to this ESP8266 // how many clients should be able to telnet to this ESP8266
#define MAX_SRV_CLIENTS 2 #define MAX_SRV_CLIENTS 2
const char* ssid = STASSID; const char* ssid = STASSID;
const char* password = STAPSK; const char* password = STAPSK;
@ -98,7 +98,7 @@ void setup() {
logger->printf("Serial receive buffer size: %d bytes\n", RXBUFFERSIZE); logger->printf("Serial receive buffer size: %d bytes\n", RXBUFFERSIZE);
#if SERIAL_LOOPBACK #if SERIAL_LOOPBACK
USC0(0) |= (1 << UCLBE); // incomplete HardwareSerial API USC0(0) |= (1 << UCLBE); // incomplete HardwareSerial API
logger->println("Serial Internal Loopback enabled"); logger->println("Serial Internal Loopback enabled");
#endif #endif
@ -114,7 +114,7 @@ void setup() {
logger->print("connected, address="); logger->print("connected, address=");
logger->println(WiFi.localIP()); logger->println(WiFi.localIP());
//start server // start server
server.begin(); server.begin();
server.setNoDelay(true); server.setNoDelay(true);
@ -124,19 +124,19 @@ void setup() {
} }
void loop() { void loop() {
//check if there are any new clients // check if there are any new clients
if (server.hasClient()) { if (server.hasClient()) {
//find free/disconnected spot // find free/disconnected spot
int i; int i;
for (i = 0; i < MAX_SRV_CLIENTS; i++) for (i = 0; i < MAX_SRV_CLIENTS; i++)
if (!serverClients[i]) { // equivalent to !serverClients[i].connected() if (!serverClients[i]) { // equivalent to !serverClients[i].connected()
serverClients[i] = server.accept(); serverClients[i] = server.accept();
logger->print("New client: index "); logger->print("New client: index ");
logger->print(i); logger->print(i);
break; break;
} }
//no free/disconnected spot so reject // no free/disconnected spot so reject
if (i == MAX_SRV_CLIENTS) { if (i == MAX_SRV_CLIENTS) {
server.accept().println("busy"); server.accept().println("busy");
// hints: server.accept() is a WiFiClient with short-term scope // hints: server.accept() is a WiFiClient with short-term scope
@ -147,7 +147,7 @@ void loop() {
} }
} }
//check TCP clients for data // check TCP clients for data
#if 1 #if 1
// Incredibly, this code is faster than the buffered one below - #4620 is needed // Incredibly, this code is faster than the buffered one below - #4620 is needed
// loopback/3000000baud average 348KB/s // loopback/3000000baud average 348KB/s
@ -165,9 +165,7 @@ void loop() {
uint8_t buf[maxToSerial]; uint8_t buf[maxToSerial];
size_t tcp_got = serverClients[i].read(buf, maxToSerial); size_t tcp_got = serverClients[i].read(buf, maxToSerial);
size_t serial_sent = Serial.write(buf, tcp_got); size_t serial_sent = Serial.write(buf, tcp_got);
if (serial_sent != maxToSerial) { if (serial_sent != maxToSerial) { logger->printf("len mismatch: available:%zd tcp-read:%zd serial-write:%zd\n", maxToSerial, tcp_got, serial_sent); }
logger->printf("len mismatch: available:%zd tcp-read:%zd serial-write:%zd\n", maxToSerial, tcp_got, serial_sent);
}
} }
#endif #endif
@ -189,7 +187,7 @@ void loop() {
} }
} }
//check UART for data // check UART for data
size_t len = std::min(Serial.available(), maxToTcp); size_t len = std::min(Serial.available(), maxToTcp);
len = std::min(len, (size_t)STACK_PROTECTOR); len = std::min(len, (size_t)STACK_PROTECTOR);
if (len) { if (len) {
@ -202,9 +200,7 @@ void loop() {
// ensure write space is sufficient: // ensure write space is sufficient:
if (serverClients[i].availableForWrite() >= serial_got) { if (serverClients[i].availableForWrite() >= serial_got) {
size_t tcp_sent = serverClients[i].write(sbuf, serial_got); size_t tcp_sent = serverClients[i].write(sbuf, serial_got);
if (tcp_sent != len) { if (tcp_sent != len) { logger->printf("len mismatch: available:%zd serial-read:%zd tcp-write:%zd\n", len, serial_got, tcp_sent); }
logger->printf("len mismatch: available:%zd serial-read:%zd tcp-write:%zd\n", len, serial_got, tcp_sent);
}
} }
} }
} }

View File

@ -1,4 +1,4 @@
#define ESP8266WIFIMESH_DISABLE_COMPATIBILITY // Excludes redundant compatibility code. TODO: Should be used for new code until the compatibility code is removed with release 3.0.0 of the Arduino core. #define ESP8266WIFIMESH_DISABLE_COMPATIBILITY // Excludes redundant compatibility code. TODO: Should be used for new code until the compatibility code is removed with release 3.0.0 of the Arduino core.
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <EspnowMeshBackend.h> #include <EspnowMeshBackend.h>
@ -19,26 +19,23 @@ namespace TypeCast = MeshTypeConversionFunctions;
https://github.com/esp8266/Arduino/issues/1143 https://github.com/esp8266/Arduino/issues/1143
https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html
*/ */
constexpr char exampleMeshName[] PROGMEM = "MeshNode_"; // The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example networkFilter and broadcastFilter functions below. constexpr char exampleMeshName[] PROGMEM = "MeshNode_"; // The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example networkFilter and broadcastFilter functions below.
constexpr char exampleWiFiPassword[] PROGMEM = "ChangeThisWiFiPassword_TODO"; // Note: " is an illegal character. The password has to be min 8 and max 64 characters long, otherwise an AP which uses it will not be found during scans. constexpr char exampleWiFiPassword[] PROGMEM = "ChangeThisWiFiPassword_TODO"; // Note: " is an illegal character. The password has to be min 8 and max 64 characters long, otherwise an AP which uses it will not be found during scans.
// A custom encryption key is required when using encrypted ESP-NOW transmissions. There is always a default Kok set, but it can be replaced if desired. // A custom encryption key is required when using encrypted ESP-NOW transmissions. There is always a default Kok set, but it can be replaced if desired.
// All ESP-NOW keys below must match in an encrypted connection pair for encrypted communication to be possible. // All ESP-NOW keys below must match in an encrypted connection pair for encrypted communication to be possible.
// Note that it is also possible to use Strings as key seeds instead of arrays. // Note that it is also possible to use Strings as key seeds instead of arrays.
uint8_t espnowEncryptedConnectionKey[16] = {0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, // This is the key for encrypting transmissions of encrypted connections. uint8_t espnowEncryptedConnectionKey[16] = { 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, // This is the key for encrypting transmissions of encrypted connections.
0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x32, 0x11 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x32, 0x11 };
}; uint8_t espnowEncryptionKok[16] = { 0x22, 0x44, 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, // This is the key for encrypting the encrypted connection key.
uint8_t espnowEncryptionKok[16] = {0x22, 0x44, 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, // This is the key for encrypting the encrypted connection key. 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x32, 0x33 };
0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x32, 0x33 uint8_t espnowHashKey[16] = { 0xEF, 0x44, 0x33, 0x0C, 0x33, 0x44, 0xFE, 0x44, // This is the secret key used for HMAC during encrypted connection requests.
}; 0x33, 0x44, 0x33, 0xB0, 0x33, 0x44, 0x32, 0xAD };
uint8_t espnowHashKey[16] = {0xEF, 0x44, 0x33, 0x0C, 0x33, 0x44, 0xFE, 0x44, // This is the secret key used for HMAC during encrypted connection requests.
0x33, 0x44, 0x33, 0xB0, 0x33, 0x44, 0x32, 0xAD
};
unsigned int requestNumber = 0; unsigned int requestNumber = 0;
unsigned int responseNumber = 0; unsigned int responseNumber = 0;
const char broadcastMetadataDelimiter = 23; // 23 = End-of-Transmission-Block (ETB) control character in ASCII const char broadcastMetadataDelimiter = 23; // 23 = End-of-Transmission-Block (ETB) control character in ASCII
String manageRequest(const String &request, MeshBackendBase &meshInstance); String manageRequest(const String &request, MeshBackendBase &meshInstance);
TransmissionStatusType manageResponse(const String &response, MeshBackendBase &meshInstance); TransmissionStatusType manageResponse(const String &response, MeshBackendBase &meshInstance);
@ -61,7 +58,7 @@ String manageRequest(const String &request, MeshBackendBase &meshInstance) {
String transmissionEncrypted = espnowInstance->receivedEncryptedTransmission() ? F(", Encrypted transmission") : F(", Unencrypted transmission"); String transmissionEncrypted = espnowInstance->receivedEncryptedTransmission() ? F(", Encrypted transmission") : F(", Unencrypted transmission");
Serial.print(String(F("ESP-NOW (")) + espnowInstance->getSenderMac() + transmissionEncrypted + F("): ")); Serial.print(String(F("ESP-NOW (")) + espnowInstance->getSenderMac() + transmissionEncrypted + F("): "));
} else if (TcpIpMeshBackend *tcpIpInstance = TypeCast::meshBackendCast<TcpIpMeshBackend *>(&meshInstance)) { } else if (TcpIpMeshBackend *tcpIpInstance = TypeCast::meshBackendCast<TcpIpMeshBackend *>(&meshInstance)) {
(void)tcpIpInstance; // This is useful to remove a "unused parameter" compiler warning. Does nothing else. (void)tcpIpInstance; // This is useful to remove a "unused parameter" compiler warning. Does nothing else.
Serial.print(F("TCP/IP: ")); Serial.print(F("TCP/IP: "));
} else { } else {
Serial.print(F("UNKNOWN!: ")); Serial.print(F("UNKNOWN!: "));
@ -174,7 +171,7 @@ bool broadcastFilter(String &firstTransmission, EspnowMeshBackend &meshInstance)
String targetMeshName = firstTransmission.substring(0, metadataEndIndex); String targetMeshName = firstTransmission.substring(0, metadataEndIndex);
if (!targetMeshName.isEmpty() && meshInstance.getMeshName() != targetMeshName) { if (!targetMeshName.isEmpty() && meshInstance.getMeshName() != targetMeshName) {
return false; // Broadcast is for another mesh network return false; // Broadcast is for another mesh network
} else { } else {
// Remove metadata from message and mark as accepted broadcast. // Remove metadata from message and mark as accepted broadcast.
// Note that when you modify firstTransmission it is best to avoid using substring or other String methods that rely on null values for String length determination. // Note that when you modify firstTransmission it is best to avoid using substring or other String methods that rely on null values for String length determination.
@ -198,7 +195,7 @@ bool broadcastFilter(String &firstTransmission, EspnowMeshBackend &meshInstance)
bool exampleTransmissionOutcomesUpdateHook(MeshBackendBase &meshInstance) { bool exampleTransmissionOutcomesUpdateHook(MeshBackendBase &meshInstance) {
// Currently this is exactly the same as the default hook, but you can modify it to alter the behaviour of attemptTransmission. // Currently this is exactly the same as the default hook, but you can modify it to alter the behaviour of attemptTransmission.
(void)meshInstance; // This is useful to remove a "unused parameter" compiler warning. Does nothing else. (void)meshInstance; // This is useful to remove a "unused parameter" compiler warning. Does nothing else.
return true; return true;
} }
@ -221,7 +218,7 @@ bool exampleTransmissionOutcomesUpdateHook(MeshBackendBase &meshInstance) {
bool exampleResponseTransmittedHook(bool transmissionSuccessful, const String &response, const uint8_t *recipientMac, uint32_t responseIndex, EspnowMeshBackend &meshInstance) { bool exampleResponseTransmittedHook(bool transmissionSuccessful, const String &response, const uint8_t *recipientMac, uint32_t responseIndex, EspnowMeshBackend &meshInstance) {
// Currently this is exactly the same as the default hook, but you can modify it to alter the behaviour of sendEspnowResponses. // Currently this is exactly the same as the default hook, but you can modify it to alter the behaviour of sendEspnowResponses.
(void)transmissionSuccessful; // This is useful to remove a "unused parameter" compiler warning. Does nothing else. (void)transmissionSuccessful; // This is useful to remove a "unused parameter" compiler warning. Does nothing else.
(void)response; (void)response;
(void)recipientMac; (void)recipientMac;
(void)responseIndex; (void)responseIndex;
@ -281,8 +278,8 @@ void setup() {
// Uncomment the lines below to use automatic AEAD encryption/decryption of messages sent/received. // Uncomment the lines below to use automatic AEAD encryption/decryption of messages sent/received.
// All nodes this node wishes to communicate with must then also use encrypted messages with the same getEspnowMessageEncryptionKey(), or messages will not be accepted. // All nodes this node wishes to communicate with must then also use encrypted messages with the same getEspnowMessageEncryptionKey(), or messages will not be accepted.
// Note that using AEAD encrypted messages will reduce the number of message bytes that can be transmitted. // Note that using AEAD encrypted messages will reduce the number of message bytes that can be transmitted.
//espnowNode.setEspnowMessageEncryptionKey(F("ChangeThisKeySeed_TODO")); // The message encryption key should always be set manually. Otherwise a default key (all zeroes) is used. // espnowNode.setEspnowMessageEncryptionKey(F("ChangeThisKeySeed_TODO")); // The message encryption key should always be set manually. Otherwise a default key (all zeroes) is used.
//espnowNode.setUseEncryptedMessages(true); // espnowNode.setUseEncryptedMessages(true);
} }
int32_t timeOfLastScan = -10000; int32_t timeOfLastScan = -10000;
@ -293,10 +290,10 @@ void loop() {
// Note that depending on the amount of responses to send and their length, this method can take tens or even hundreds of milliseconds to complete. // Note that depending on the amount of responses to send and their length, this method can take tens or even hundreds of milliseconds to complete.
// More intense transmission activity and less frequent calls to performEspnowMaintenance will likely cause the method to take longer to complete, so plan accordingly. // More intense transmission activity and less frequent calls to performEspnowMaintenance will likely cause the method to take longer to complete, so plan accordingly.
//Should not be used inside responseHandler, requestHandler, networkFilter or broadcastFilter callbacks since performEspnowMaintenance() can alter the ESP-NOW state. // Should not be used inside responseHandler, requestHandler, networkFilter or broadcastFilter callbacks since performEspnowMaintenance() can alter the ESP-NOW state.
EspnowMeshBackend::performEspnowMaintenance(); EspnowMeshBackend::performEspnowMaintenance();
if (millis() - timeOfLastScan > 10000) { // Give other nodes some time to connect between data transfers. if (millis() - timeOfLastScan > 10000) { // Give other nodes some time to connect between data transfers.
Serial.println(F("\nPerforming unencrypted ESP-NOW transmissions.")); Serial.println(F("\nPerforming unencrypted ESP-NOW transmissions."));
uint32_t startTime = millis(); uint32_t startTime = millis();
@ -310,9 +307,7 @@ void loop() {
espnowDelay(100); espnowDelay(100);
// One way to check how attemptTransmission worked out // One way to check how attemptTransmission worked out
if (espnowNode.latestTransmissionSuccessful()) { if (espnowNode.latestTransmissionSuccessful()) { Serial.println(F("Transmission successful.")); }
Serial.println(F("Transmission successful."));
}
// Another way to check how attemptTransmission worked out // Another way to check how attemptTransmission worked out
if (espnowNode.latestTransmissionOutcomes().empty()) { if (espnowNode.latestTransmissionOutcomes().empty()) {
@ -343,20 +338,20 @@ void loop() {
espnowNode.broadcast(broadcastMetadata + broadcastMessage); espnowNode.broadcast(broadcastMetadata + broadcastMessage);
Serial.println(String(F("Broadcast to all mesh nodes done in ")) + String(millis() - startTime) + F(" ms.")); Serial.println(String(F("Broadcast to all mesh nodes done in ")) + String(millis() - startTime) + F(" ms."));
espnowDelay(100); // Wait for responses (broadcasts can receive an unlimited number of responses, other transmissions can only receive one response). espnowDelay(100); // Wait for responses (broadcasts can receive an unlimited number of responses, other transmissions can only receive one response).
// If you have a data array containing null values it is possible to transmit the raw data by making the array into a multiString as shown below. // If you have a data array containing null values it is possible to transmit the raw data by making the array into a multiString as shown below.
// You can use String::c_str() or String::begin() to retrieve the data array later. // You can use String::c_str() or String::begin() to retrieve the data array later.
// Note that certain String methods such as String::substring use null values to determine String length, which means they will not work as normal with multiStrings. // Note that certain String methods such as String::substring use null values to determine String length, which means they will not work as normal with multiStrings.
uint8_t dataArray[] = {0, '\'', 0, '\'', ' ', '(', 'n', 'u', 'l', 'l', ')', ' ', 'v', 'a', 'l', 'u', 'e'}; uint8_t dataArray[] = { 0, '\'', 0, '\'', ' ', '(', 'n', 'u', 'l', 'l', ')', ' ', 'v', 'a', 'l', 'u', 'e' };
String espnowMessage = TypeCast::uint8ArrayToMultiString(dataArray, sizeof dataArray) + F(" from ") + espnowNode.getMeshName() + espnowNode.getNodeID() + String('.'); String espnowMessage = TypeCast::uint8ArrayToMultiString(dataArray, sizeof dataArray) + F(" from ") + espnowNode.getMeshName() + espnowNode.getNodeID() + String('.');
Serial.println(String(F("\nTransmitting: ")) + espnowMessage); Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
espnowNode.attemptTransmission(espnowMessage, false); espnowNode.attemptTransmission(espnowMessage, false);
espnowDelay(100); // Wait for response. espnowDelay(100); // Wait for response.
Serial.println(F("\nPerforming encrypted ESP-NOW transmissions.")); Serial.println(F("\nPerforming encrypted ESP-NOW transmissions."));
uint8_t targetBSSID[6] {0}; uint8_t targetBSSID[6]{ 0 };
// We can create encrypted connections to individual nodes so that all ESP-NOW communication with the node will be encrypted. // We can create encrypted connections to individual nodes so that all ESP-NOW communication with the node will be encrypted.
if (espnowNode.constConnectionQueue()[0].getBSSID(targetBSSID) && espnowNode.requestEncryptedConnection(targetBSSID) == EncryptedConnectionStatus::CONNECTION_ESTABLISHED) { if (espnowNode.constConnectionQueue()[0].getBSSID(targetBSSID) && espnowNode.requestEncryptedConnection(targetBSSID) == EncryptedConnectionStatus::CONNECTION_ESTABLISHED) {
@ -369,7 +364,7 @@ void loop() {
String espnowMessage = String(F("This message is encrypted only when received by node ")) + peerMac; String espnowMessage = String(F("This message is encrypted only when received by node ")) + peerMac;
Serial.println(String(F("\nTransmitting: ")) + espnowMessage); Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
espnowNode.attemptTransmission(espnowMessage, false); espnowNode.attemptTransmission(espnowMessage, false);
espnowDelay(100); // Wait for response. espnowDelay(100); // Wait for response.
// A connection can be serialized and stored for later use. // A connection can be serialized and stored for later use.
// Note that this saves the current state only, so if encrypted communication between the nodes happen after this, the stored state is invalid. // Note that this saves the current state only, so if encrypted communication between the nodes happen after this, the stored state is invalid.
@ -383,7 +378,7 @@ void loop() {
espnowMessage = String(F("This message is no longer encrypted when received by node ")) + peerMac; espnowMessage = String(F("This message is no longer encrypted when received by node ")) + peerMac;
Serial.println(String(F("\nTransmitting: ")) + espnowMessage); Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
espnowNode.attemptTransmission(espnowMessage, false); espnowNode.attemptTransmission(espnowMessage, false);
espnowDelay(100); // Wait for response. espnowDelay(100); // Wait for response.
Serial.println(F("Cannot read the encrypted response...")); Serial.println(F("Cannot read the encrypted response..."));
// Let's re-add our stored connection so we can communicate properly with targetBSSID again! // Let's re-add our stored connection so we can communicate properly with targetBSSID again!
@ -392,7 +387,7 @@ void loop() {
espnowMessage = String(F("This message is once again encrypted when received by node ")) + peerMac; espnowMessage = String(F("This message is once again encrypted when received by node ")) + peerMac;
Serial.println(String(F("\nTransmitting: ")) + espnowMessage); Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
espnowNode.attemptTransmission(espnowMessage, false); espnowNode.attemptTransmission(espnowMessage, false);
espnowDelay(100); // Wait for response. espnowDelay(100); // Wait for response.
Serial.println(); Serial.println();
// If we want to remove the encrypted connection on both nodes, we can do it like this. // If we want to remove the encrypted connection on both nodes, we can do it like this.
@ -403,7 +398,7 @@ void loop() {
espnowMessage = String(F("This message is only received by node ")) + peerMac + F(". Transmitting in this way will not change the transmission state of the sender."); espnowMessage = String(F("This message is only received by node ")) + peerMac + F(". Transmitting in this way will not change the transmission state of the sender.");
Serial.println(String(F("Transmitting: ")) + espnowMessage); Serial.println(String(F("Transmitting: ")) + espnowMessage);
espnowNode.attemptTransmission(espnowMessage, EspnowNetworkInfo(targetBSSID)); espnowNode.attemptTransmission(espnowMessage, EspnowNetworkInfo(targetBSSID));
espnowDelay(100); // Wait for response. espnowDelay(100); // Wait for response.
Serial.println(); Serial.println();
@ -423,7 +418,7 @@ void loop() {
espnowMessage = String(F("Due to encrypted connection expiration, this message is no longer encrypted when received by node ")) + peerMac; espnowMessage = String(F("Due to encrypted connection expiration, this message is no longer encrypted when received by node ")) + peerMac;
Serial.println(String(F("\nTransmitting: ")) + espnowMessage); Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
espnowNode.attemptTransmission(espnowMessage, false); espnowNode.attemptTransmission(espnowMessage, false);
espnowDelay(100); // Wait for response. espnowDelay(100); // Wait for response.
} }
// Or if we prefer we can just let the library automatically create brief encrypted connections which are long enough to transmit an encrypted message. // Or if we prefer we can just let the library automatically create brief encrypted connections which are long enough to transmit an encrypted message.
@ -432,9 +427,9 @@ void loop() {
espnowMessage = F("This message is always encrypted, regardless of receiver."); espnowMessage = F("This message is always encrypted, regardless of receiver.");
Serial.println(String(F("\nTransmitting: ")) + espnowMessage); Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
espnowNode.attemptAutoEncryptingTransmission(espnowMessage); espnowNode.attemptAutoEncryptingTransmission(espnowMessage);
espnowDelay(100); // Wait for response. espnowDelay(100); // Wait for response.
} else { } else {
Serial.println(String(F("Ooops! Encrypted connection removal failed. Status: ")) + String(static_cast<int>(removalOutcome))); Serial.println(String(F("Ooops! Encrypted connection removal failed. Status: ")) + String(static_cast<int>(removalOutcome)));
} }
// Finally, should you ever want to stop other parties from sending unencrypted messages to the node // Finally, should you ever want to stop other parties from sending unencrypted messages to the node
@ -445,8 +440,7 @@ void loop() {
} }
// Our last request was sent to all nodes found, so time to create a new request. // Our last request was sent to all nodes found, so time to create a new request.
espnowNode.setMessage(String(F("Hello world request #")) + String(++requestNumber) + F(" from ") espnowNode.setMessage(String(F("Hello world request #")) + String(++requestNumber) + F(" from ") + espnowNode.getMeshName() + espnowNode.getNodeID() + String('.'));
+ espnowNode.getMeshName() + espnowNode.getNodeID() + String('.'));
} }
Serial.println(); Serial.println();

View File

@ -8,7 +8,7 @@
Or "floodingMesh.getEspnowMeshBackend().setBroadcastTransmissionRedundancy(uint8_t redundancy)" (default 1) at the cost of longer transmission times. Or "floodingMesh.getEspnowMeshBackend().setBroadcastTransmissionRedundancy(uint8_t redundancy)" (default 1) at the cost of longer transmission times.
*/ */
#define ESP8266WIFIMESH_DISABLE_COMPATIBILITY // Excludes redundant compatibility code. TODO: Should be used for new code until the compatibility code is removed with release 3.0.0 of the Arduino core. #define ESP8266WIFIMESH_DISABLE_COMPATIBILITY // Excludes redundant compatibility code. TODO: Should be used for new code until the compatibility code is removed with release 3.0.0 of the Arduino core.
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <TypeConversionFunctions.h> #include <TypeConversionFunctions.h>
@ -28,18 +28,16 @@ namespace TypeCast = MeshTypeConversionFunctions;
https://github.com/esp8266/Arduino/issues/1143 https://github.com/esp8266/Arduino/issues/1143
https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html
*/ */
constexpr char exampleMeshName[] PROGMEM = "MeshNode_"; // The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example networkFilter and broadcastFilter functions below. constexpr char exampleMeshName[] PROGMEM = "MeshNode_"; // The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example networkFilter and broadcastFilter functions below.
constexpr char exampleWiFiPassword[] PROGMEM = "ChangeThisWiFiPassword_TODO"; // Note: " is an illegal character. The password has to be min 8 and max 64 characters long, otherwise an AP which uses it will not be found during scans. constexpr char exampleWiFiPassword[] PROGMEM = "ChangeThisWiFiPassword_TODO"; // Note: " is an illegal character. The password has to be min 8 and max 64 characters long, otherwise an AP which uses it will not be found during scans.
// A custom encryption key is required when using encrypted ESP-NOW transmissions. There is always a default Kok set, but it can be replaced if desired. // A custom encryption key is required when using encrypted ESP-NOW transmissions. There is always a default Kok set, but it can be replaced if desired.
// All ESP-NOW keys below must match in an encrypted connection pair for encrypted communication to be possible. // All ESP-NOW keys below must match in an encrypted connection pair for encrypted communication to be possible.
// Note that it is also possible to use Strings as key seeds instead of arrays. // Note that it is also possible to use Strings as key seeds instead of arrays.
uint8_t espnowEncryptedConnectionKey[16] = {0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, // This is the key for encrypting transmissions of encrypted connections. uint8_t espnowEncryptedConnectionKey[16] = { 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, // This is the key for encrypting transmissions of encrypted connections.
0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x32, 0x11 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x32, 0x11 };
}; uint8_t espnowHashKey[16] = { 0xEF, 0x44, 0x33, 0x0C, 0x33, 0x44, 0xFE, 0x44, // This is the secret key used for HMAC during encrypted connection requests.
uint8_t espnowHashKey[16] = {0xEF, 0x44, 0x33, 0x0C, 0x33, 0x44, 0xFE, 0x44, // This is the secret key used for HMAC during encrypted connection requests. 0x33, 0x44, 0x33, 0xB0, 0x33, 0x44, 0x32, 0xAD };
0x33, 0x44, 0x33, 0xB0, 0x33, 0x44, 0x32, 0xAD
};
bool meshMessageHandler(String &message, FloodingMesh &meshInstance); bool meshMessageHandler(String &message, FloodingMesh &meshInstance);
@ -49,7 +47,7 @@ FloodingMesh floodingMesh = FloodingMesh(meshMessageHandler, FPSTR(exampleWiFiPa
bool theOne = true; bool theOne = true;
String theOneMac; String theOneMac;
bool useLED = false; // Change this to true if you wish the onboard LED to mark The One. bool useLED = false; // Change this to true if you wish the onboard LED to mark The One.
/** /**
Callback for when a message is received from the mesh network. Callback for when a message is received from the mesh network.
@ -78,7 +76,7 @@ bool meshMessageHandler(String &message, FloodingMesh &meshInstance) {
if (useLED && !theOne) { if (useLED && !theOne) {
bool ledState = message.charAt(1) == '1'; bool ledState = message.charAt(1) == '1';
digitalWrite(LED_BUILTIN, ledState); // Turn LED on/off (LED_BUILTIN is active low) digitalWrite(LED_BUILTIN, ledState); // Turn LED on/off (LED_BUILTIN is active low)
} }
return true; return true;
@ -87,26 +85,22 @@ bool meshMessageHandler(String &message, FloodingMesh &meshInstance) {
} }
} else if (delimiterIndex > 0) { } else if (delimiterIndex > 0) {
if (meshInstance.getOriginMac() == theOneMac) { if (meshInstance.getOriginMac() == theOneMac) {
uint32_t totalBroadcasts = strtoul(message.c_str(), nullptr, 0); // strtoul stops reading input when an invalid character is discovered. uint32_t totalBroadcasts = strtoul(message.c_str(), nullptr, 0); // strtoul stops reading input when an invalid character is discovered.
// Static variables are only initialized once. // Static variables are only initialized once.
static uint32_t firstBroadcast = totalBroadcasts; static uint32_t firstBroadcast = totalBroadcasts;
if (totalBroadcasts - firstBroadcast >= 100) { // Wait a little to avoid start-up glitches if (totalBroadcasts - firstBroadcast >= 100) { // Wait a little to avoid start-up glitches
static uint32_t missedBroadcasts = 1; // Starting at one to compensate for initial -1 below. static uint32_t missedBroadcasts = 1; // Starting at one to compensate for initial -1 below.
static uint32_t previousTotalBroadcasts = totalBroadcasts; static uint32_t previousTotalBroadcasts = totalBroadcasts;
static uint32_t totalReceivedBroadcasts = 0; static uint32_t totalReceivedBroadcasts = 0;
totalReceivedBroadcasts++; totalReceivedBroadcasts++;
missedBroadcasts += totalBroadcasts - previousTotalBroadcasts - 1; // We expect an increment by 1. missedBroadcasts += totalBroadcasts - previousTotalBroadcasts - 1; // We expect an increment by 1.
previousTotalBroadcasts = totalBroadcasts; previousTotalBroadcasts = totalBroadcasts;
if (totalReceivedBroadcasts % 50 == 0) { if (totalReceivedBroadcasts % 50 == 0) { Serial.println(String(F("missed/total: ")) + String(missedBroadcasts) + '/' + String(totalReceivedBroadcasts)); }
Serial.println(String(F("missed/total: ")) + String(missedBroadcasts) + '/' + String(totalReceivedBroadcasts)); if (totalReceivedBroadcasts % 500 == 0) { Serial.println(String(F("Benchmark message: ")) + message.substring(0, 100)); }
}
if (totalReceivedBroadcasts % 500 == 0) {
Serial.println(String(F("Benchmark message: ")) + message.substring(0, 100));
}
} }
} }
} else { } else {
@ -136,24 +130,24 @@ void setup() {
Serial.println(F("Setting up mesh node...")); Serial.println(F("Setting up mesh node..."));
floodingMesh.begin(); floodingMesh.begin();
floodingMesh.activateAP(); // Required to receive messages floodingMesh.activateAP(); // Required to receive messages
uint8_t apMacArray[6] {0}; uint8_t apMacArray[6]{ 0 };
theOneMac = TypeCast::macToString(WiFi.softAPmacAddress(apMacArray)); theOneMac = TypeCast::macToString(WiFi.softAPmacAddress(apMacArray));
if (useLED) { if (useLED) {
pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output
digitalWrite(LED_BUILTIN, LOW); // Turn LED on (LED_BUILTIN is active low) digitalWrite(LED_BUILTIN, LOW); // Turn LED on (LED_BUILTIN is active low)
} }
// Uncomment the lines below to use automatic AEAD encryption/decryption of messages sent/received via broadcast() and encryptedBroadcast(). // Uncomment the lines below to use automatic AEAD encryption/decryption of messages sent/received via broadcast() and encryptedBroadcast().
// The main benefit of AEAD encryption is that it can be used with normal broadcasts (which are substantially faster than encryptedBroadcasts). // The main benefit of AEAD encryption is that it can be used with normal broadcasts (which are substantially faster than encryptedBroadcasts).
// The main drawbacks are that AEAD only encrypts the message data (not transmission metadata), transfers less data per message and lacks replay attack protection. // The main drawbacks are that AEAD only encrypts the message data (not transmission metadata), transfers less data per message and lacks replay attack protection.
// When using AEAD, potential replay attacks must thus be handled manually. // When using AEAD, potential replay attacks must thus be handled manually.
//floodingMesh.getEspnowMeshBackend().setEspnowMessageEncryptionKey(F("ChangeThisKeySeed_TODO")); // The message encryption key should always be set manually. Otherwise a default key (all zeroes) is used. // floodingMesh.getEspnowMeshBackend().setEspnowMessageEncryptionKey(F("ChangeThisKeySeed_TODO")); // The message encryption key should always be set manually. Otherwise a default key (all zeroes) is used.
//floodingMesh.getEspnowMeshBackend().setUseEncryptedMessages(true); // floodingMesh.getEspnowMeshBackend().setUseEncryptedMessages(true);
floodingMeshDelay(5000); // Give some time for user to start the nodes floodingMeshDelay(5000); // Give some time for user to start the nodes
} }
int32_t timeOfLastProclamation = -10000; int32_t timeOfLastProclamation = -10000;
@ -177,7 +171,7 @@ void loop() {
if (theOne) { if (theOne) {
if (millis() - timeOfLastProclamation > 10000) { if (millis() - timeOfLastProclamation > 10000) {
uint32_t startTime = millis(); uint32_t startTime = millis();
ledState = ledState ^ bool(benchmarkCount); // Make other nodes' LEDs alternate between on and off once benchmarking begins. ledState = ledState ^ bool(benchmarkCount); // Make other nodes' LEDs alternate between on and off once benchmarking begins.
// Note: The maximum length of an unencrypted broadcast message is given by floodingMesh.maxUnencryptedMessageLength(). It is around 670 bytes by default. // Note: The maximum length of an unencrypted broadcast message is given by floodingMesh.maxUnencryptedMessageLength(). It is around 670 bytes by default.
floodingMesh.broadcast(String(floodingMesh.metadataDelimiter()) + String(ledState) + theOneMac + F(" is The One.")); floodingMesh.broadcast(String(floodingMesh.metadataDelimiter()) + String(ledState) + theOneMac + F(" is The One."));
@ -187,7 +181,7 @@ void loop() {
floodingMeshDelay(20); floodingMeshDelay(20);
} }
if (millis() - loopStart > 23000) { // Start benchmarking the mesh once three proclamations have been made if (millis() - loopStart > 23000) { // Start benchmarking the mesh once three proclamations have been made
uint32_t startTime = millis(); uint32_t startTime = millis();
floodingMesh.broadcast(String(benchmarkCount++) + String(floodingMesh.metadataDelimiter()) + F(": Not a spoon in sight.")); floodingMesh.broadcast(String(benchmarkCount++) + String(floodingMesh.metadataDelimiter()) + F(": Not a spoon in sight."));
Serial.println(String(F("Benchmark broadcast done in ")) + String(millis() - startTime) + F(" ms.")); Serial.println(String(F("Benchmark broadcast done in ")) + String(millis() - startTime) + F(" ms."));

View File

@ -1,4 +1,4 @@
#define ESP8266WIFIMESH_DISABLE_COMPATIBILITY // Excludes redundant compatibility code. TODO: Should be used for new code until the compatibility code is removed with release 3.0.0 of the Arduino core. #define ESP8266WIFIMESH_DISABLE_COMPATIBILITY // Excludes redundant compatibility code. TODO: Should be used for new code until the compatibility code is removed with release 3.0.0 of the Arduino core.
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <TcpIpMeshBackend.h> #include <TcpIpMeshBackend.h>
@ -20,7 +20,7 @@ namespace TypeCast = MeshTypeConversionFunctions;
https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html
*/ */
constexpr char exampleMeshName[] PROGMEM = "MeshNode_"; constexpr char exampleMeshName[] PROGMEM = "MeshNode_";
constexpr char exampleWiFiPassword[] PROGMEM = "ChangeThisWiFiPassword_TODO"; // Note: " is an illegal character. The password has to be min 8 and max 64 characters long, otherwise an AP which uses it will not be found during scans. constexpr char exampleWiFiPassword[] PROGMEM = "ChangeThisWiFiPassword_TODO"; // Note: " is an illegal character. The password has to be min 8 and max 64 characters long, otherwise an AP which uses it will not be found during scans.
unsigned int requestNumber = 0; unsigned int requestNumber = 0;
unsigned int responseNumber = 0; unsigned int responseNumber = 0;
@ -45,7 +45,7 @@ String manageRequest(const String &request, MeshBackendBase &meshInstance) {
String transmissionEncrypted = espnowInstance->receivedEncryptedTransmission() ? F(", Encrypted transmission") : F(", Unencrypted transmission"); String transmissionEncrypted = espnowInstance->receivedEncryptedTransmission() ? F(", Encrypted transmission") : F(", Unencrypted transmission");
Serial.print(String(F("ESP-NOW (")) + espnowInstance->getSenderMac() + transmissionEncrypted + F("): ")); Serial.print(String(F("ESP-NOW (")) + espnowInstance->getSenderMac() + transmissionEncrypted + F("): "));
} else if (TcpIpMeshBackend *tcpIpInstance = TypeCast::meshBackendCast<TcpIpMeshBackend *>(&meshInstance)) { } else if (TcpIpMeshBackend *tcpIpInstance = TypeCast::meshBackendCast<TcpIpMeshBackend *>(&meshInstance)) {
(void)tcpIpInstance; // This is useful to remove a "unused parameter" compiler warning. Does nothing else. (void)tcpIpInstance; // This is useful to remove a "unused parameter" compiler warning. Does nothing else.
Serial.print(F("TCP/IP: ")); Serial.print(F("TCP/IP: "));
} else { } else {
Serial.print(F("UNKNOWN!: ")); Serial.print(F("UNKNOWN!: "));
@ -145,8 +145,7 @@ bool exampleTransmissionOutcomesUpdateHook(MeshBackendBase &meshInstance) {
if (TcpIpMeshBackend *tcpIpInstance = TypeCast::meshBackendCast<TcpIpMeshBackend *>(&meshInstance)) { if (TcpIpMeshBackend *tcpIpInstance = TypeCast::meshBackendCast<TcpIpMeshBackend *>(&meshInstance)) {
if (tcpIpInstance->latestTransmissionOutcomes().back().transmissionStatus() == TransmissionStatusType::TRANSMISSION_COMPLETE) { if (tcpIpInstance->latestTransmissionOutcomes().back().transmissionStatus() == TransmissionStatusType::TRANSMISSION_COMPLETE) {
// Our last request got a response, so time to create a new request. // Our last request got a response, so time to create a new request.
meshInstance.setMessage(String(F("Hello world request #")) + String(++requestNumber) + F(" from ") meshInstance.setMessage(String(F("Hello world request #")) + String(++requestNumber) + F(" from ") + meshInstance.getMeshName() + meshInstance.getNodeID() + String('.'));
+ meshInstance.getMeshName() + meshInstance.getNodeID() + String('.'));
} }
} else { } else {
Serial.println(F("Invalid mesh backend!")); Serial.println(F("Invalid mesh backend!"));
@ -174,8 +173,8 @@ void setup() {
/* Initialise the mesh node */ /* Initialise the mesh node */
tcpIpNode.begin(); tcpIpNode.begin();
tcpIpNode.activateAP(); // Each AP requires a separate server port. tcpIpNode.activateAP(); // Each AP requires a separate server port.
tcpIpNode.setStaticIP(IPAddress(192, 168, 4, 22)); // Activate static IP mode to speed up connection times. tcpIpNode.setStaticIP(IPAddress(192, 168, 4, 22)); // Activate static IP mode to speed up connection times.
// Storing our message in the TcpIpMeshBackend instance is not required, but can be useful for organizing code, especially when using many TcpIpMeshBackend instances. // Storing our message in the TcpIpMeshBackend instance is not required, but can be useful for organizing code, especially when using many TcpIpMeshBackend instances.
// Note that calling the multi-recipient tcpIpNode.attemptTransmission will replace the stored message with whatever message is transmitted. // Note that calling the multi-recipient tcpIpNode.attemptTransmission will replace the stored message with whatever message is transmitted.
@ -186,17 +185,15 @@ void setup() {
int32_t timeOfLastScan = -10000; int32_t timeOfLastScan = -10000;
void loop() { void loop() {
if (millis() - timeOfLastScan > 3000 // Give other nodes some time to connect between data transfers. if (millis() - timeOfLastScan > 3000 // Give other nodes some time to connect between data transfers.
|| (WiFi.status() != WL_CONNECTED && millis() - timeOfLastScan > 2000)) { // Scan for networks with two second intervals when not already connected. || (WiFi.status() != WL_CONNECTED && millis() - timeOfLastScan > 2000)) { // Scan for networks with two second intervals when not already connected.
// attemptTransmission(message, scan, scanAllWiFiChannels, concludingDisconnect, initialDisconnect = false) // attemptTransmission(message, scan, scanAllWiFiChannels, concludingDisconnect, initialDisconnect = false)
tcpIpNode.attemptTransmission(tcpIpNode.getMessage(), true, false, false); tcpIpNode.attemptTransmission(tcpIpNode.getMessage(), true, false, false);
timeOfLastScan = millis(); timeOfLastScan = millis();
// One way to check how attemptTransmission worked out // One way to check how attemptTransmission worked out
if (tcpIpNode.latestTransmissionSuccessful()) { if (tcpIpNode.latestTransmissionSuccessful()) { Serial.println(F("Transmission successful.")); }
Serial.println(F("Transmission successful."));
}
// Another way to check how attemptTransmission worked out // Another way to check how attemptTransmission worked out
if (tcpIpNode.latestTransmissionOutcomes().empty()) { if (tcpIpNode.latestTransmissionOutcomes().empty()) {

View File

@ -15,7 +15,7 @@
#ifndef APSSID #ifndef APSSID
#define APSSID "APSSID" #define APSSID "APSSID"
#define APPSK "APPSK" #define APPSK "APPSK"
#endif #endif
ESP8266WiFiMulti WiFiMulti; ESP8266WiFiMulti WiFiMulti;
@ -37,8 +37,6 @@ void setup() {
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFiMulti.addAP(APSSID, APPSK); WiFiMulti.addAP(APSSID, APPSK);
} }
void update_started() { void update_started() {
@ -80,21 +78,14 @@ void loop() {
t_httpUpdate_return ret = ESPhttpUpdate.update(client, "http://server/file.bin"); t_httpUpdate_return ret = ESPhttpUpdate.update(client, "http://server/file.bin");
// Or: // Or:
//t_httpUpdate_return ret = ESPhttpUpdate.update(client, "server", 80, "file.bin"); // t_httpUpdate_return ret = ESPhttpUpdate.update(client, "server", 80, "file.bin");
switch (ret) { switch (ret) {
case HTTP_UPDATE_FAILED: case HTTP_UPDATE_FAILED: Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str()); break;
Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES: case HTTP_UPDATE_NO_UPDATES: Serial.println("HTTP_UPDATE_NO_UPDATES"); break;
Serial.println("HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK: case HTTP_UPDATE_OK: Serial.println("HTTP_UPDATE_OK"); break;
Serial.println("HTTP_UPDATE_OK");
break;
} }
} }
} }

View File

@ -17,7 +17,7 @@ ESP8266WiFiMulti WiFiMulti;
#ifndef APSSID #ifndef APSSID
#define APSSID "APSSID" #define APSSID "APSSID"
#define APPSK "APPSK" #define APPSK "APPSK"
#endif #endif
void setup() { void setup() {
@ -37,7 +37,6 @@ void setup() {
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFiMulti.addAP(APSSID, APPSK); WiFiMulti.addAP(APSSID, APPSK);
} }
void loop() { void loop() {
@ -62,19 +61,12 @@ void loop() {
ret = ESPhttpUpdate.update(client, "http://server/file.bin"); ret = ESPhttpUpdate.update(client, "http://server/file.bin");
switch (ret) { switch (ret) {
case HTTP_UPDATE_FAILED: case HTTP_UPDATE_FAILED: Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str()); break;
Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES: case HTTP_UPDATE_NO_UPDATES: Serial.println("HTTP_UPDATE_NO_UPDATES"); break;
Serial.println("HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK: case HTTP_UPDATE_OK: Serial.println("HTTP_UPDATE_OK"); break;
Serial.println("HTTP_UPDATE_OK");
break;
} }
} }
} }
} }

View File

@ -18,7 +18,7 @@
#ifndef APSSID #ifndef APSSID
#define APSSID "APSSID" #define APSSID "APSSID"
#define APPSK "APPSK" #define APPSK "APPSK"
#endif #endif
ESP8266WiFiMulti WiFiMulti; ESP8266WiFiMulti WiFiMulti;
@ -74,7 +74,7 @@ void setup() {
Serial.println(numCerts); Serial.println(numCerts);
if (numCerts == 0) { if (numCerts == 0) {
Serial.println(F("No certs found. Did you run certs-from-mozill.py and upload the LittleFS directory before running?")); Serial.println(F("No certs found. Did you run certs-from-mozill.py and upload the LittleFS directory before running?"));
return; // Can't connect to anything w/o certs! return; // Can't connect to anything w/o certs!
} }
} }
@ -87,9 +87,7 @@ void loop() {
BearSSL::WiFiClientSecure client; BearSSL::WiFiClientSecure client;
bool mfln = client.probeMaxFragmentLength("server", 443, 1024); // server must be the same as in ESPhttpUpdate.update() bool mfln = client.probeMaxFragmentLength("server", 443, 1024); // server must be the same as in ESPhttpUpdate.update()
Serial.printf("MFLN supported: %s\n", mfln ? "yes" : "no"); Serial.printf("MFLN supported: %s\n", mfln ? "yes" : "no");
if (mfln) { if (mfln) { client.setBufferSizes(1024, 1024); }
client.setBufferSizes(1024, 1024);
}
client.setCertStore(&certStore); client.setCertStore(&certStore);
// The line below is optional. It can be used to blink the LED on the board during flashing // The line below is optional. It can be used to blink the LED on the board during flashing
@ -102,21 +100,15 @@ void loop() {
t_httpUpdate_return ret = ESPhttpUpdate.update(client, "https://server/file.bin"); t_httpUpdate_return ret = ESPhttpUpdate.update(client, "https://server/file.bin");
// Or: // Or:
//t_httpUpdate_return ret = ESPhttpUpdate.update(client, "server", 443, "file.bin"); // t_httpUpdate_return ret = ESPhttpUpdate.update(client, "server", 443, "file.bin");
switch (ret) { switch (ret) {
case HTTP_UPDATE_FAILED: case HTTP_UPDATE_FAILED: Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str()); break;
Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES: case HTTP_UPDATE_NO_UPDATES: Serial.println("HTTP_UPDATE_NO_UPDATES"); break;
Serial.println("HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK: case HTTP_UPDATE_OK: Serial.println("HTTP_UPDATE_OK"); break;
Serial.println("HTTP_UPDATE_OK");
break;
} }
} }
} }

View File

@ -23,7 +23,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
ESP8266WiFiMulti WiFiMulti; ESP8266WiFiMulti WiFiMulti;
@ -73,11 +73,11 @@ void setup() {
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFiMulti.addAP(STASSID, STAPSK); WiFiMulti.addAP(STASSID, STAPSK);
#if MANUAL_SIGNING #if MANUAL_SIGNING
signPubKey = new BearSSL::PublicKey(pubkey); signPubKey = new BearSSL::PublicKey(pubkey);
hash = new BearSSL::HashSHA256(); hash = new BearSSL::HashSHA256();
sign = new BearSSL::SigningVerifier(signPubKey); sign = new BearSSL::SigningVerifier(signPubKey);
#endif #endif
} }
@ -87,10 +87,10 @@ void loop() {
WiFiClient client; WiFiClient client;
#if MANUAL_SIGNING #if MANUAL_SIGNING
// Ensure all updates are signed appropriately. W/o this call, all will be accepted. // Ensure all updates are signed appropriately. W/o this call, all will be accepted.
Update.installSignature(hash, sign); Update.installSignature(hash, sign);
#endif #endif
// If the key files are present in the build directory, signing will be // If the key files are present in the build directory, signing will be
// enabled using them automatically // enabled using them automatically
@ -99,19 +99,12 @@ void loop() {
t_httpUpdate_return ret = ESPhttpUpdate.update(client, "http://192.168.1.8/esp8266.bin"); t_httpUpdate_return ret = ESPhttpUpdate.update(client, "http://192.168.1.8/esp8266.bin");
switch (ret) { switch (ret) {
case HTTP_UPDATE_FAILED: case HTTP_UPDATE_FAILED: Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str()); break;
Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES: case HTTP_UPDATE_NO_UPDATES: Serial.println("HTTP_UPDATE_NO_UPDATES"); break;
Serial.println("HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK: case HTTP_UPDATE_OK: Serial.println("HTTP_UPDATE_OK"); break;
Serial.println("HTTP_UPDATE_OK");
break;
} }
} }
delay(10000); delay(10000);
} }

View File

@ -43,39 +43,38 @@
Global defines and vars Global defines and vars
*/ */
#define TIMEZONE_OFFSET 1 // CET #define TIMEZONE_OFFSET 1 // CET
#define DST_OFFSET 1 // CEST #define DST_OFFSET 1 // CEST
#define UPDATE_CYCLE (1 * 1000) // every second #define UPDATE_CYCLE (1 * 1000) // every second
#define SERVICE_PORT 80 // HTTP port #define SERVICE_PORT 80 // HTTP port
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
const char* password = STAPSK; const char* password = STAPSK;
char* pcHostDomain = 0; // Negotiated host domain char* pcHostDomain = 0; // Negotiated host domain
bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain
MDNSResponder::hMDNSService hMDNSService = 0; // The handle of the clock service in the MDNS responder MDNSResponder::hMDNSService hMDNSService = 0; // The handle of the clock service in the MDNS responder
// HTTP server at port 'SERVICE_PORT' will respond to HTTP requests // HTTP server at port 'SERVICE_PORT' will respond to HTTP requests
ESP8266WebServer server(SERVICE_PORT); ESP8266WebServer server(SERVICE_PORT);
/* /*
getTimeString getTimeString
*/ */
const char* getTimeString(void) { const char* getTimeString(void) {
static char acTimeString[32]; static char acTimeString[32];
time_t now = time(nullptr); time_t now = time(nullptr);
ctime_r(&now, acTimeString); ctime_r(&now, acTimeString);
size_t stLength; size_t stLength;
while (((stLength = strlen(acTimeString))) && while (((stLength = strlen(acTimeString))) && ('\n' == acTimeString[stLength - 1])) {
('\n' == acTimeString[stLength - 1])) { acTimeString[stLength - 1] = 0; // Remove trailing line break...
acTimeString[stLength - 1] = 0; // Remove trailing line break...
} }
return acTimeString; return acTimeString;
} }
@ -186,7 +185,8 @@ void handleHTTPRequest() {
Serial.println("HTTP Request"); Serial.println("HTTP Request");
// Get current time // Get current time
time_t now = time(nullptr);; time_t now = time(nullptr);
;
struct tm timeinfo; struct tm timeinfo;
gmtime_r(&now, &timeinfo); gmtime_r(&now, &timeinfo);
@ -231,10 +231,9 @@ void setup(void) {
// Setup MDNS responder // Setup MDNS responder
MDNS.setHostProbeResultCallback(hostProbeResult); MDNS.setHostProbeResultCallback(hostProbeResult);
// Init the (currently empty) host domain string with 'esp8266' // Init the (currently empty) host domain string with 'esp8266'
if ((!MDNSResponder::indexDomain(pcHostDomain, 0, "esp8266")) || if ((!MDNSResponder::indexDomain(pcHostDomain, 0, "esp8266")) || (!MDNS.begin(pcHostDomain))) {
(!MDNS.begin(pcHostDomain))) {
Serial.println("Error setting up MDNS responder!"); Serial.println("Error setting up MDNS responder!");
while (1) { // STOP while (1) { // STOP
delay(1000); delay(1000);
} }
} }

View File

@ -39,26 +39,26 @@
Global defines and vars Global defines and vars
*/ */
#define SERVICE_PORT 80 // HTTP port #define SERVICE_PORT 80 // HTTP port
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
const char* password = STAPSK; const char* password = STAPSK;
char* pcHostDomain = 0; // Negotiated host domain char* pcHostDomain = 0; // Negotiated host domain
bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain
MDNSResponder::hMDNSService hMDNSService = 0; // The handle of the http service in the MDNS responder MDNSResponder::hMDNSService hMDNSService = 0; // The handle of the http service in the MDNS responder
MDNSResponder::hMDNSServiceQuery hMDNSServiceQuery = 0; // The handle of the 'http.tcp' service query in the MDNS responder MDNSResponder::hMDNSServiceQuery hMDNSServiceQuery = 0; // The handle of the 'http.tcp' service query in the MDNS responder
const String cstrNoHTTPServices = "Currently no 'http.tcp' services in the local network!<br/>"; const String cstrNoHTTPServices = "Currently no 'http.tcp' services in the local network!<br/>";
String strHTTPServices = cstrNoHTTPServices; String strHTTPServices = cstrNoHTTPServices;
// HTTP server at port 'SERVICE_PORT' will respond to HTTP requests // HTTP server at port 'SERVICE_PORT' will respond to HTTP requests
ESP8266WebServer server(SERVICE_PORT); ESP8266WebServer server(SERVICE_PORT);
/* /*
@ -80,26 +80,17 @@ bool setStationHostname(const char* p_pcHostname) {
void MDNSServiceQueryCallback(MDNSResponder::MDNSServiceInfo serviceInfo, MDNSResponder::AnswerType answerType, bool p_bSetContent) { void MDNSServiceQueryCallback(MDNSResponder::MDNSServiceInfo serviceInfo, MDNSResponder::AnswerType answerType, bool p_bSetContent) {
String answerInfo; String answerInfo;
switch (answerType) { switch (answerType) {
case MDNSResponder::AnswerType::ServiceDomain : case MDNSResponder::AnswerType::ServiceDomain: answerInfo = "ServiceDomain " + String(serviceInfo.serviceDomain()); break;
answerInfo = "ServiceDomain " + String(serviceInfo.serviceDomain()); case MDNSResponder::AnswerType::HostDomainAndPort: answerInfo = "HostDomainAndPort " + String(serviceInfo.hostDomain()) + ":" + String(serviceInfo.hostPort()); break;
break; case MDNSResponder::AnswerType::IP4Address:
case MDNSResponder::AnswerType::HostDomainAndPort :
answerInfo = "HostDomainAndPort " + String(serviceInfo.hostDomain()) + ":" + String(serviceInfo.hostPort());
break;
case MDNSResponder::AnswerType::IP4Address :
answerInfo = "IP4Address "; answerInfo = "IP4Address ";
for (IPAddress ip : serviceInfo.IP4Adresses()) { for (IPAddress ip : serviceInfo.IP4Adresses()) { answerInfo += "- " + ip.toString(); };
answerInfo += "- " + ip.toString();
};
break; break;
case MDNSResponder::AnswerType::Txt : case MDNSResponder::AnswerType::Txt:
answerInfo = "TXT " + String(serviceInfo.strKeyValue()); answerInfo = "TXT " + String(serviceInfo.strKeyValue());
for (auto kv : serviceInfo.keyValues()) { for (auto kv : serviceInfo.keyValues()) { answerInfo += "\nkv : " + String(kv.first) + " : " + String(kv.second); }
answerInfo += "\nkv : " + String(kv.first) + " : " + String(kv.second);
}
break; break;
default : default: answerInfo = "Unknown Answertype";
answerInfo = "Unknown Answertype";
} }
Serial.printf("Answer %s %s\n", answerInfo.c_str(), p_bSetContent ? "Modified" : "Deleted"); Serial.printf("Answer %s %s\n", answerInfo.c_str(), p_bSetContent ? "Modified" : "Deleted");
} }
@ -109,10 +100,8 @@ void MDNSServiceQueryCallback(MDNSResponder::MDNSServiceInfo serviceInfo, MDNSRe
Probe result callback for Services Probe result callback for Services
*/ */
void serviceProbeResult(String p_pcServiceName, void serviceProbeResult(String p_pcServiceName, const MDNSResponder::hMDNSService p_hMDNSService, bool p_bProbeResult) {
const MDNSResponder::hMDNSService p_hMDNSService, (void)p_hMDNSService;
bool p_bProbeResult) {
(void) p_hMDNSService;
Serial.printf("MDNSServiceProbeResultCallback: Service %s probe %s\n", p_pcServiceName.c_str(), (p_bProbeResult ? "succeeded." : "failed!")); Serial.printf("MDNSServiceProbeResultCallback: Service %s probe %s\n", p_pcServiceName.c_str(), (p_bProbeResult ? "succeeded." : "failed!"));
} }
@ -186,7 +175,7 @@ void handleHTTPRequest() {
s += WiFi.hostname() + ".local at " + WiFi.localIP().toString() + "</h3></head>"; s += WiFi.hostname() + ".local at " + WiFi.localIP().toString() + "</h3></head>";
s += "<br/><h4>Local HTTP services are :</h4>"; s += "<br/><h4>Local HTTP services are :</h4>";
s += "<ol>"; s += "<ol>";
for (auto info : MDNS.answerInfo(hMDNSServiceQuery)) { for (auto info : MDNS.answerInfo(hMDNSServiceQuery)) {
s += "<li>"; s += "<li>";
s += info.serviceDomain(); s += info.serviceDomain();
if (info.hostDomainAvailable()) { if (info.hostDomainAvailable()) {
@ -196,15 +185,11 @@ void handleHTTPRequest() {
} }
if (info.IP4AddressAvailable()) { if (info.IP4AddressAvailable()) {
s += "<br/>IP4:"; s += "<br/>IP4:";
for (auto ip : info.IP4Adresses()) { for (auto ip : info.IP4Adresses()) { s += " " + ip.toString(); }
s += " " + ip.toString();
}
} }
if (info.txtAvailable()) { if (info.txtAvailable()) {
s += "<br/>TXT:<br/>"; s += "<br/>TXT:<br/>";
for (auto kv : info.keyValues()) { for (auto kv : info.keyValues()) { s += "\t" + String(kv.first) + " : " + String(kv.second) + "<br/>"; }
s += "\t" + String(kv.first) + " : " + String(kv.second) + "<br/>";
}
} }
s += "</li>"; s += "</li>";
} }
@ -245,10 +230,9 @@ void setup(void) {
MDNS.setHostProbeResultCallback(hostProbeResult); MDNS.setHostProbeResultCallback(hostProbeResult);
// Init the (currently empty) host domain string with 'esp8266' // Init the (currently empty) host domain string with 'esp8266'
if ((!MDNSResponder::indexDomain(pcHostDomain, 0, "esp8266")) || if ((!MDNSResponder::indexDomain(pcHostDomain, 0, "esp8266")) || (!MDNS.begin(pcHostDomain))) {
(!MDNS.begin(pcHostDomain))) {
Serial.println(" Error setting up MDNS responder!"); Serial.println(" Error setting up MDNS responder!");
while (1) { // STOP while (1) { // STOP
delay(1000); delay(1000);
} }
} }
@ -265,6 +249,3 @@ void loop(void) {
// Allow MDNS processing // Allow MDNS processing
MDNS.update(); MDNS.update();
} }

View File

@ -14,12 +14,12 @@
#ifndef APSSID #ifndef APSSID
#define APSSID "your-apssid" #define APSSID "your-apssid"
#define APPSK "your-password" #define APPSK "your-password"
#endif #endif
#ifndef STASSID #ifndef STASSID
#define STASSID "your-sta" #define STASSID "your-sta"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
// includes // includes
@ -35,15 +35,15 @@
@brief mDNS and OTA Constants @brief mDNS and OTA Constants
@{ @{
*/ */
#define HOSTNAME "ESP8266-OTA-" ///< Hostname. The setup function adds the Chip ID at the end. #define HOSTNAME "ESP8266-OTA-" ///< Hostname. The setup function adds the Chip ID at the end.
/// @} /// @}
/** /**
@brief Default WiFi connection information. @brief Default WiFi connection information.
@{ @{
*/ */
const char* ap_default_ssid = APSSID; ///< Default SSID. const char *ap_default_ssid = APSSID; ///< Default SSID.
const char* ap_default_psk = APPSK; ///< Default PSK. const char *ap_default_psk = APPSK; ///< Default PSK.
/// @} /// @}
/// Uncomment the next line for verbose output over UART. /// Uncomment the next line for verbose output over UART.
@ -81,9 +81,7 @@ bool loadConfig(String *ssid, String *pass) {
if (pos == -1) { if (pos == -1) {
le = 1; le = 1;
pos = content.indexOf("\n"); pos = content.indexOf("\n");
if (pos == -1) { if (pos == -1) { pos = content.indexOf("\r"); }
pos = content.indexOf("\r");
}
} }
// If there is no second line: Some information is missing. // If there is no second line: Some information is missing.
@ -110,7 +108,7 @@ bool loadConfig(String *ssid, String *pass) {
#endif #endif
return true; return true;
} // loadConfig } // loadConfig
/** /**
@ -135,7 +133,7 @@ bool saveConfig(String *ssid, String *pass) {
configFile.close(); configFile.close();
return true; return true;
} // saveConfig } // saveConfig
/** /**
@ -160,7 +158,7 @@ void setup() {
// Print hostname. // Print hostname.
Serial.println("Hostname: " + hostname); Serial.println("Hostname: " + hostname);
//Serial.println(WiFi.hostname()); // Serial.println(WiFi.hostname());
// Initialize file system. // Initialize file system.
@ -170,7 +168,7 @@ void setup() {
} }
// Load wifi connection information. // Load wifi connection information.
if (! loadConfig(&station_ssid, &station_psk)) { if (!loadConfig(&station_ssid, &station_psk)) {
station_ssid = STASSID; station_ssid = STASSID;
station_psk = STAPSK; station_psk = STAPSK;
@ -196,7 +194,7 @@ void setup() {
Serial.println(WiFi.SSID()); Serial.println(WiFi.SSID());
// ... Uncomment this for debugging output. // ... Uncomment this for debugging output.
//WiFi.printDiag(Serial); // WiFi.printDiag(Serial);
} else { } else {
// ... Begin with sdk config. // ... Begin with sdk config.
WiFi.begin(); WiFi.begin();
@ -208,7 +206,7 @@ void setup() {
unsigned long startTime = millis(); unsigned long startTime = millis();
while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000) { while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000) {
Serial.write('.'); Serial.write('.');
//Serial.print(WiFi.status()); // Serial.print(WiFi.status());
delay(500); delay(500);
} }
Serial.println(); Serial.println();
@ -245,4 +243,3 @@ void loop() {
// Handle OTA server. // Handle OTA server.
ArduinoOTA.handle(); ArduinoOTA.handle();
} }

View File

@ -14,12 +14,12 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
const char* password = STAPSK; const char* password = STAPSK;
char hostString[16] = {0}; char hostString[16] = { 0 };
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
@ -43,14 +43,12 @@ void setup() {
Serial.print("IP address: "); Serial.print("IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
if (!MDNS.begin(hostString)) { if (!MDNS.begin(hostString)) { Serial.println("Error setting up MDNS responder!"); }
Serial.println("Error setting up MDNS responder!");
}
Serial.println("mDNS responder started"); Serial.println("mDNS responder started");
MDNS.addService("esp", "tcp", 8080); // Announce esp tcp service on port 8080 MDNS.addService("esp", "tcp", 8080); // Announce esp tcp service on port 8080
Serial.println("Sending mDNS query"); Serial.println("Sending mDNS query");
int n = MDNS.queryService("esp", "tcp"); // Send out query for esp tcp services int n = MDNS.queryService("esp", "tcp"); // Send out query for esp tcp services
Serial.println("mDNS query done"); Serial.println("mDNS query done");
if (n == 0) { if (n == 0) {
Serial.println("no services found"); Serial.println("no services found");

View File

@ -22,7 +22,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
@ -57,9 +57,7 @@ void setup(void) {
// we send our IP address on the WiFi network // we send our IP address on the WiFi network
if (!MDNS.begin("esp8266")) { if (!MDNS.begin("esp8266")) {
Serial.println("Error setting up MDNS responder!"); Serial.println("Error setting up MDNS responder!");
while (1) { while (1) { delay(1000); }
delay(1000);
}
} }
Serial.println("mDNS responder started"); Serial.println("mDNS responder started");
@ -77,16 +75,12 @@ void loop(void) {
// Check if a client has connected // Check if a client has connected
WiFiClient client = server.accept(); WiFiClient client = server.accept();
if (!client) { if (!client) { return; }
return;
}
Serial.println(""); Serial.println("");
Serial.println("New client"); Serial.println("New client");
// Wait for data from client to become available // Wait for data from client to become available
while (client.connected() && !client.available()) { while (client.connected() && !client.available()) { delay(1); }
delay(1);
}
// Read the first line of HTTP request // Read the first line of HTTP request
String req = client.readStringUntil('\r'); String req = client.readStringUntil('\r');
@ -121,4 +115,3 @@ void loop(void) {
Serial.println("Done with client"); Serial.println("Done with client");
} }

View File

@ -30,4 +30,3 @@
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
MDNSResponder MDNS; MDNSResponder MDNS;
#endif #endif

View File

@ -3,15 +3,19 @@
This file is part of the esp8266 core for Arduino environment. This file is part of the esp8266 core for Arduino environment.
mDNS implementation, that supports many mDNS features like: mDNS implementation, that supports many mDNS features like:
- Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service - Presenting a DNS-SD service to interested observers, eg. a http server by presenting
- Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented _http._tcp service
- Support for multi-level compressed names in input; in output only a very simple one-leven
full-name compression is implemented
- Probing host and service domains for uniqueness in the local network - Probing host and service domains for uniqueness in the local network
- Tiebreaking while probing is supported in a very minimalistic way (the 'higher' IP address wins the tiebreak) - Tiebreaking while probing is supported in a very minimalistic way (the 'higher' IP address
wins the tiebreak)
- Announcing available services after successful probing - Announcing available services after successful probing
- Using fixed service TXT items or - Using fixed service TXT items or
- Using dynamic service TXT items for presented services (via callback) - Using dynamic service TXT items for presented services (via callback)
- Remove services (and un-announcing them to the observers by sending goodbye-messages) - Remove services (and un-announcing them to the observers by sending goodbye-messages)
- Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period) - Static queries for DNS-SD services (creating a fixed answer set after a certain timeout
period)
- Dynamic queries for DNS-SD services with cached and updated answers and user notifications - Dynamic queries for DNS-SD services with cached and updated answers and user notifications
- Support for multi-homed client host domains - Support for multi-homed client host domains
@ -41,13 +45,13 @@
#ifndef __ESP8266MDNS_H #ifndef __ESP8266MDNS_H
#define __ESP8266MDNS_H #define __ESP8266MDNS_H
#include "LEAmDNS.h" // LEA #include "LEAmDNS.h" // LEA
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
// Maps the implementation to use to the global namespace type // Maps the implementation to use to the global namespace type
using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; // LEA using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; // LEA
extern MDNSResponder MDNS; extern MDNSResponder MDNS;
#endif #endif
#endif // __ESP8266MDNS_H #endif // __ESP8266MDNS_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@ namespace MDNSImplementation
// Enable class debug functions // Enable class debug functions
#define ESP_8266_MDNS_INCLUDE #define ESP_8266_MDNS_INCLUDE
//#define DEBUG_ESP_MDNS_RESPONDER //#define DEBUG_ESP_MDNS_RESPONDER
#if !defined(DEBUG_ESP_MDNS_RESPONDER) && defined(DEBUG_ESP_MDNS) #if !defined(DEBUG_ESP_MDNS_RESPONDER) && defined(DEBUG_ESP_MDNS)
#define DEBUG_ESP_MDNS_RESPONDER #define DEBUG_ESP_MDNS_RESPONDER
@ -48,8 +48,9 @@ namespace MDNSImplementation
#endif #endif
// //
// If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful probing // If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful
// This allows to drive the responder in a environment, where 'update()' isn't called in the loop // probing This allows to drive the responder in a environment, where 'update()' isn't called in the
// loop
//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE //#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE
// Enable/disable debug trace macros // Enable/disable debug trace macros
@ -62,7 +63,7 @@ namespace MDNSImplementation
#ifdef DEBUG_ESP_MDNS_RESPONDER #ifdef DEBUG_ESP_MDNS_RESPONDER
#ifdef DEBUG_ESP_MDNS_INFO #ifdef DEBUG_ESP_MDNS_INFO
#define DEBUG_EX_INFO(A) A #define DEBUG_EX_INFO(A) A
#else #else
#define DEBUG_EX_INFO(A) #define DEBUG_EX_INFO(A)
#endif #endif
@ -72,12 +73,12 @@ namespace MDNSImplementation
#define DEBUG_EX_ERR(A) #define DEBUG_EX_ERR(A)
#endif #endif
#ifdef DEBUG_ESP_MDNS_TX #ifdef DEBUG_ESP_MDNS_TX
#define DEBUG_EX_TX(A) A #define DEBUG_EX_TX(A) A
#else #else
#define DEBUG_EX_TX(A) #define DEBUG_EX_TX(A)
#endif #endif
#ifdef DEBUG_ESP_MDNS_RX #ifdef DEBUG_ESP_MDNS_RX
#define DEBUG_EX_RX(A) A #define DEBUG_EX_RX(A) A
#else #else
#define DEBUG_EX_RX(A) #define DEBUG_EX_RX(A)
#endif #endif
@ -88,19 +89,34 @@ namespace MDNSImplementation
#define DEBUG_OUTPUT Serial #define DEBUG_OUTPUT Serial
#endif #endif
#else #else
#define DEBUG_EX_INFO(A) do { (void)0; } while (0) #define DEBUG_EX_INFO(A) \
#define DEBUG_EX_ERR(A) do { (void)0; } while (0) do \
#define DEBUG_EX_TX(A) do { (void)0; } while (0) { \
#define DEBUG_EX_RX(A) do { (void)0; } while (0) (void)0; \
} while (0)
#define DEBUG_EX_ERR(A) \
do \
{ \
(void)0; \
} while (0)
#define DEBUG_EX_TX(A) \
do \
{ \
(void)0; \
} while (0)
#define DEBUG_EX_RX(A) \
do \
{ \
(void)0; \
} while (0)
#endif #endif
/* already defined in lwIP ('lwip/prot/dns.h') /* already defined in lwIP ('lwip/prot/dns.h')
#ifdef MDNS_IP4_SUPPORT #ifdef MDNS_IP4_SUPPORT
#define DNS_MQUERY_IPV4_GROUP_INIT (IPAddress(224, 0, 0, 251)) // ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT #define DNS_MQUERY_IPV4_GROUP_INIT (IPAddress(224, 0, 0, 251)) // ip_addr_t
#endif v4group = DNS_MQUERY_IPV4_GROUP_INIT #endif #ifdef MDNS_IP6_SUPPORT #define
#ifdef MDNS_IP6_SUPPORT DNS_MQUERY_IPV6_GROUP_INIT IPADDR6_INIT_HOST(0xFF020000,0,0,0xFB) // ip_addr_t v6group =
#define DNS_MQUERY_IPV6_GROUP_INIT IPADDR6_INIT_HOST(0xFF020000,0,0,0xFB) // ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT DNS_MQUERY_IPV6_GROUP_INIT #endif*/
#endif*/
//#define MDNS_MULTICAST_PORT 5353 //#define MDNS_MULTICAST_PORT 5353
/* /*
@ -111,44 +127,44 @@ namespace MDNSImplementation
However, RFC 3171 seems to force 255 instead However, RFC 3171 seems to force 255 instead
*/ */
#define MDNS_MULTICAST_TTL 255/*1*/ #define MDNS_MULTICAST_TTL 255 /*1*/
/* /*
This is the MDNS record TTL This is the MDNS record TTL
Host level records are set to 2min (120s) Host level records are set to 2min (120s)
service level records are set to 75min (4500s) service level records are set to 75min (4500s)
*/ */
#define MDNS_HOST_TTL 120 #define MDNS_HOST_TTL 120
#define MDNS_SERVICE_TTL 4500 #define MDNS_SERVICE_TTL 4500
/* /*
Compressed labels are flagged by the two topmost bits of the length byte being set Compressed labels are flagged by the two topmost bits of the length byte being set
*/ */
#define MDNS_DOMAIN_COMPRESS_MARK 0xC0 #define MDNS_DOMAIN_COMPRESS_MARK 0xC0
/* /*
Avoid endless recursion because of malformed compressed labels Avoid endless recursion because of malformed compressed labels
*/ */
#define MDNS_DOMAIN_MAX_REDIRCTION 6 #define MDNS_DOMAIN_MAX_REDIRCTION 6
/* /*
Default service priority and weight in SRV answers Default service priority and weight in SRV answers
*/ */
#define MDNS_SRV_PRIORITY 0 #define MDNS_SRV_PRIORITY 0
#define MDNS_SRV_WEIGHT 0 #define MDNS_SRV_WEIGHT 0
/* /*
Delay between and number of probes for host and service domains Delay between and number of probes for host and service domains
Delay between and number of announces for host and service domains Delay between and number of announces for host and service domains
Delay between and number of service queries; the delay is multiplied by the resent number in '_checkServiceQueryCache' Delay between and number of service queries; the delay is multiplied by the resent number in
'_checkServiceQueryCache'
*/ */
#define MDNS_PROBE_DELAY 250 #define MDNS_PROBE_DELAY 250
#define MDNS_PROBE_COUNT 3 #define MDNS_PROBE_COUNT 3
#define MDNS_ANNOUNCE_DELAY 1000 #define MDNS_ANNOUNCE_DELAY 1000
#define MDNS_ANNOUNCE_COUNT 8 #define MDNS_ANNOUNCE_COUNT 8
#define MDNS_DYNAMIC_QUERY_RESEND_COUNT 5 #define MDNS_DYNAMIC_QUERY_RESEND_COUNT 5
#define MDNS_DYNAMIC_QUERY_RESEND_DELAY 5000 #define MDNS_DYNAMIC_QUERY_RESEND_DELAY 5000
/* /*
Force host domain to use only lowercase letters Force host domain to use only lowercase letters
*/ */
@ -167,15 +183,14 @@ namespace MDNSImplementation
#ifdef F #ifdef F
#undef F #undef F
#endif #endif
#define F(A) A #define F(A) A
#endif #endif
} // namespace MDNSImplementation } // namespace MDNSImplementation
} // namespace esp8266 } // namespace esp8266
// Include the main header, so the submodlues only need to include this header // Include the main header, so the submodlues only need to include this header
#include "LEAmDNS.h" #include "LEAmDNS.h"
#endif // MDNS_PRIV_H #endif // MDNS_PRIV_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -27,4 +27,4 @@
#include <lwip/prot/dns.h> // DNS_RRTYPE_xxx, DNS_MQUERY_PORT #include <lwip/prot/dns.h> // DNS_RRTYPE_xxx, DNS_MQUERY_PORT
#endif // MDNS_LWIPDEFS_H #endif // MDNS_LWIPDEFS_H

View File

@ -22,9 +22,7 @@ void loop() {
sha1("test", &hash[0]); sha1("test", &hash[0]);
Serial.print("SHA1:"); Serial.print("SHA1:");
for (uint16_t i = 0; i < 20; i++) { for (uint16_t i = 0; i < 20; i++) { Serial.printf("%02x", hash[i]); }
Serial.printf("%02x", hash[i]);
}
Serial.println(); Serial.println();
delay(1000); delay(1000);

View File

@ -15,13 +15,14 @@ void setup() {
// on non-native USB ports // on non-native USB ports
Serial.begin(115200); Serial.begin(115200);
while (!Serial) { while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only ; // wait for serial port to connect. Needed for native USB port only
} }
// start I2S at 8 kHz with 24-bits per sample // start I2S at 8 kHz with 24-bits per sample
if (!I2S.begin(I2S_PHILIPS_MODE, 8000, 24)) { if (!I2S.begin(I2S_PHILIPS_MODE, 8000, 24)) {
Serial.println("Failed to initialize I2S!"); Serial.println("Failed to initialize I2S!");
while (1); // do nothing while (1)
; // do nothing
} }
} }

View File

@ -10,13 +10,13 @@
#include <I2S.h> #include <I2S.h>
const int frequency = 440; // frequency of square wave in Hz const int frequency = 440; // frequency of square wave in Hz
const int amplitude = 500; // amplitude of square wave const int amplitude = 500; // amplitude of square wave
const int sampleRate = 8000; // sample rate in Hz const int sampleRate = 8000; // sample rate in Hz
const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave
short sample = amplitude; // current sample value short sample = amplitude; // current sample value
int count = 0; int count = 0;
void setup() { void setup() {
@ -26,7 +26,8 @@ void setup() {
// start I2S at the sample rate with 16-bits per sample // start I2S at the sample rate with 16-bits per sample
if (!I2S.begin(I2S_PHILIPS_MODE, sampleRate, 16)) { if (!I2S.begin(I2S_PHILIPS_MODE, sampleRate, 16)) {
Serial.println("Failed to initialize I2S!"); Serial.println("Failed to initialize I2S!");
while (1); // do nothing while (1)
; // do nothing
} }
} }
@ -43,4 +44,3 @@ void loop() {
// increment the counter for the next sample // increment the counter for the next sample
count++; count++;
} }

View File

@ -9,7 +9,7 @@
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char *ssid = STASSID; const char *ssid = STASSID;
@ -19,7 +19,7 @@ long timezone = 2;
byte daysavetime = 1; byte daysavetime = 1;
void listDir(const char * dirname) { void listDir(const char *dirname) {
Serial.printf("Listing directory: %s\n", dirname); Serial.printf("Listing directory: %s\n", dirname);
Dir root = LittleFS.openDir(dirname); Dir root = LittleFS.openDir(dirname);
@ -33,7 +33,7 @@ void listDir(const char * dirname) {
time_t cr = file.getCreationTime(); time_t cr = file.getCreationTime();
time_t lw = file.getLastWrite(); time_t lw = file.getLastWrite();
file.close(); file.close();
struct tm * tmstruct = localtime(&cr); struct tm *tmstruct = localtime(&cr);
Serial.printf(" CREATION: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); Serial.printf(" CREATION: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
tmstruct = localtime(&lw); tmstruct = localtime(&lw);
Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
@ -41,7 +41,7 @@ void listDir(const char * dirname) {
} }
void readFile(const char * path) { void readFile(const char *path) {
Serial.printf("Reading file: %s\n", path); Serial.printf("Reading file: %s\n", path);
File file = LittleFS.open(path, "r"); File file = LittleFS.open(path, "r");
@ -51,13 +51,11 @@ void readFile(const char * path) {
} }
Serial.print("Read from file: "); Serial.print("Read from file: ");
while (file.available()) { while (file.available()) { Serial.write(file.read()); }
Serial.write(file.read());
}
file.close(); file.close();
} }
void writeFile(const char * path, const char * message) { void writeFile(const char *path, const char *message) {
Serial.printf("Writing file: %s\n", path); Serial.printf("Writing file: %s\n", path);
File file = LittleFS.open(path, "w"); File file = LittleFS.open(path, "w");
@ -70,11 +68,11 @@ void writeFile(const char * path, const char * message) {
} else { } else {
Serial.println("Write failed"); Serial.println("Write failed");
} }
delay(2000); // Make sure the CREATE and LASTWRITE times are different delay(2000); // Make sure the CREATE and LASTWRITE times are different
file.close(); file.close();
} }
void appendFile(const char * path, const char * message) { void appendFile(const char *path, const char *message) {
Serial.printf("Appending to file: %s\n", path); Serial.printf("Appending to file: %s\n", path);
File file = LittleFS.open(path, "a"); File file = LittleFS.open(path, "a");
@ -90,7 +88,7 @@ void appendFile(const char * path, const char * message) {
file.close(); file.close();
} }
void renameFile(const char * path1, const char * path2) { void renameFile(const char *path1, const char *path2) {
Serial.printf("Renaming file %s to %s\n", path1, path2); Serial.printf("Renaming file %s to %s\n", path1, path2);
if (LittleFS.rename(path1, path2)) { if (LittleFS.rename(path1, path2)) {
Serial.println("File renamed"); Serial.println("File renamed");
@ -99,7 +97,7 @@ void renameFile(const char * path1, const char * path2) {
} }
} }
void deleteFile(const char * path) { void deleteFile(const char *path) {
Serial.printf("Deleting file: %s\n", path); Serial.printf("Deleting file: %s\n", path);
if (LittleFS.remove(path)) { if (LittleFS.remove(path)) {
Serial.println("File deleted"); Serial.println("File deleted");
@ -127,7 +125,7 @@ void setup() {
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
Serial.println("Contacting Time Server"); Serial.println("Contacting Time Server");
configTime(3600 * timezone, daysavetime * 3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); configTime(3600 * timezone, daysavetime * 3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
struct tm tmstruct ; struct tm tmstruct;
delay(2000); delay(2000);
tmstruct.tm_year = 0; tmstruct.tm_year = 0;
getLocalTime(&tmstruct, 5000); getLocalTime(&tmstruct, 5000);
@ -158,9 +156,6 @@ void setup() {
} }
readFile("/hello.txt"); readFile("/hello.txt");
listDir("/"); listDir("/");
} }
void loop() { } void loop() {}

View File

@ -44,9 +44,7 @@ void DoTest(FS *fs) {
} }
uint8_t data[256]; uint8_t data[256];
for (int i = 0; i < 256; i++) { for (int i = 0; i < 256; i++) { data[i] = (uint8_t)i; }
data[i] = (uint8_t) i;
}
Serial.printf("Creating %dKB file, may take a while...\n", TESTSIZEKB); Serial.printf("Creating %dKB file, may take a while...\n", TESTSIZEKB);
unsigned long start = millis(); unsigned long start = millis();
@ -56,9 +54,7 @@ void DoTest(FS *fs) {
return; return;
} }
for (int i = 0; i < TESTSIZEKB; i++) { for (int i = 0; i < TESTSIZEKB; i++) {
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) { f.write(data, 256); }
f.write(data, 256);
}
} }
f.close(); f.close();
unsigned long stop = millis(); unsigned long stop = millis();
@ -72,9 +68,7 @@ void DoTest(FS *fs) {
start = millis(); start = millis();
f = fs->open("/testwrite.bin", "r"); f = fs->open("/testwrite.bin", "r");
for (int i = 0; i < TESTSIZEKB; i++) { for (int i = 0; i < TESTSIZEKB; i++) {
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) { f.read(data, 256); }
f.read(data, 256);
}
} }
f.close(); f.close();
stop = millis(); stop = millis();
@ -85,9 +79,7 @@ void DoTest(FS *fs) {
f = fs->open("/testwrite.bin", "r"); f = fs->open("/testwrite.bin", "r");
f.read(); f.read();
for (int i = 0; i < TESTSIZEKB; i++) { for (int i = 0; i < TESTSIZEKB; i++) {
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) { f.read(data + 1, 256); }
f.read(data + 1, 256);
}
} }
f.close(); f.close();
stop = millis(); stop = millis();
@ -115,9 +107,7 @@ void DoTest(FS *fs) {
Serial.printf("Writing 64K file in 1-byte chunks\n"); Serial.printf("Writing 64K file in 1-byte chunks\n");
start = millis(); start = millis();
f = fs->open("/test1b.bin", "w"); f = fs->open("/test1b.bin", "w");
for (int i = 0; i < 65536; i++) { for (int i = 0; i < 65536; i++) { f.write((uint8_t *)&i, 1); }
f.write((uint8_t*)&i, 1);
}
f.close(); f.close();
stop = millis(); stop = millis();
Serial.printf("==> Time to write 64KB in 1b chunks = %lu milliseconds = %s\n", stop - start, rate(start, stop, 65536)); Serial.printf("==> Time to write 64KB in 1b chunks = %lu milliseconds = %s\n", stop - start, rate(start, stop, 65536));
@ -127,7 +117,7 @@ void DoTest(FS *fs) {
f = fs->open("/test1b.bin", "r"); f = fs->open("/test1b.bin", "r");
for (int i = 0; i < 65536; i++) { for (int i = 0; i < 65536; i++) {
char c; char c;
f.read((uint8_t*)&c, 1); f.read((uint8_t *)&c, 1);
} }
f.close(); f.close();
stop = millis(); stop = millis();

View File

@ -12,7 +12,7 @@ using namespace NetCapture;
#ifndef STASSID #ifndef STASSID
#define STASSID "your-ssid" #define STASSID "your-ssid"
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
const char* ssid = STASSID; const char* ssid = STASSID;
@ -20,43 +20,36 @@ const char* password = STAPSK;
Netdump nd; Netdump nd;
//FS* filesystem = &SPIFFS; // FS* filesystem = &SPIFFS;
FS* filesystem = &LittleFS; FS* filesystem = &LittleFS;
ESP8266WebServer webServer(80); // Used for sending commands ESP8266WebServer webServer(80); // Used for sending commands
WiFiServer tcpServer(8000); // Used to show netcat option. WiFiServer tcpServer(8000); // Used to show netcat option.
File tracefile; File tracefile;
std::map<PacketType, int> packetCount; std::map<PacketType, int> packetCount;
enum class SerialOption : uint8_t { enum class SerialOption : uint8_t { AllFull,
AllFull, LocalNone,
LocalNone, HTTPChar };
HTTPChar
};
void startSerial(SerialOption option) { void startSerial(SerialOption option) {
switch (option) { switch (option) {
case SerialOption::AllFull : //All Packets, show packet summary. case SerialOption::AllFull: // All Packets, show packet summary.
nd.printDump(Serial, Packet::PacketDetail::FULL); nd.printDump(Serial, Packet::PacketDetail::FULL);
break; break;
case SerialOption::LocalNone : // Only local IP traffic, full details case SerialOption::LocalNone: // Only local IP traffic, full details
nd.printDump(Serial, Packet::PacketDetail::NONE, nd.printDump(Serial, Packet::PacketDetail::NONE, [](Packet n) {
[](Packet n) {
return (n.hasIP(WiFi.localIP())); return (n.hasIP(WiFi.localIP()));
} });
);
break; break;
case SerialOption::HTTPChar : // Only HTTP traffic, show packet content as chars case SerialOption::HTTPChar: // Only HTTP traffic, show packet content as chars
nd.printDump(Serial, Packet::PacketDetail::CHAR, nd.printDump(Serial, Packet::PacketDetail::CHAR, [](Packet n) {
[](Packet n) {
return (n.isHTTP()); return (n.isHTTP());
} });
);
break; break;
default : default: Serial.printf("No valid SerialOption provided\r\n");
Serial.printf("No valid SerialOption provided\r\n");
}; };
} }
@ -80,49 +73,39 @@ void setup(void) {
if (WiFi.waitForConnectResult() != WL_CONNECTED) { if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed, stopping sketch"); Serial.println("WiFi Failed, stopping sketch");
while (1) { while (1) { delay(1000); }
delay(1000);
}
} }
if (!MDNS.begin("netdumphost")) { if (!MDNS.begin("netdumphost")) { Serial.println("Error setting up MDNS responder!"); }
Serial.println("Error setting up MDNS responder!");
}
filesystem->begin(); filesystem->begin();
webServer.on("/list", webServer.on("/list", []() {
[]() {
Dir dir = filesystem->openDir("/"); Dir dir = filesystem->openDir("/");
String d = "<h1>File list</h1>"; String d = "<h1>File list</h1>";
while (dir.next()) { while (dir.next()) {
d.concat("<li>" + dir.fileName() + "</li>"); d.concat("<li>" + dir.fileName() + "</li>");
} }
webServer.send(200, "text.html", d); webServer.send(200, "text.html", d);
} });
);
webServer.on("/req", webServer.on("/req", []() {
[]() {
static int rq = 0; static int rq = 0;
String a = "<h1>You are connected, Number of requests = " + String(rq++) + "</h1>"; String a = "<h1>You are connected, Number of requests = " + String(rq++) + "</h1>";
webServer.send(200, "text/html", a); webServer.send(200, "text/html", a);
} });
);
webServer.on("/reset", webServer.on("/reset", []() {
[]() {
nd.reset(); nd.reset();
tracefile.close(); tracefile.close();
tcpServer.close(); tcpServer.close();
webServer.send(200, "text.html", "<h1>Netdump session reset</h1>"); webServer.send(200, "text.html", "<h1>Netdump session reset</h1>");
} });
);
webServer.serveStatic("/", *filesystem, "/"); webServer.serveStatic("/", *filesystem, "/");
webServer.begin(); webServer.begin();
startSerial(SerialOption::AllFull); // Serial output examples, use enum SerialOption for selection startSerial(SerialOption::AllFull); // Serial output examples, use enum SerialOption for selection
// startTcpDump(); // tcpdump option // startTcpDump(); // tcpdump option
// startTracefile(); // output to SPIFFS or LittleFS // startTracefile(); // output to SPIFFS or LittleFS
@ -132,18 +115,18 @@ void setup(void) {
nd.setCallback( nd.setCallback(
[](Packet p) [](Packet p)
{ {
Serial.printf("PKT : %s : ",p.sourceIP().toString().c_str()); Serial.printf("PKT : %s : ",p.sourceIP().toString().c_str());
for ( auto pp : p.allPacketTypes()) for ( auto pp : p.allPacketTypes())
{ {
Serial.printf("%s ",pp.toString().c_str()); Serial.printf("%s ",pp.toString().c_str());
packetCount[pp]++; packetCount[pp]++;
} }
Serial.printf("\r\n CNT "); Serial.printf("\r\n CNT ");
for (auto pc : packetCount) for (auto pc : packetCount)
{ {
Serial.printf("%s %d ", pc.first.toString().c_str(),pc.second); Serial.printf("%s %d ", pc.first.toString().c_str(),pc.second);
} }
Serial.printf("\r\n"); Serial.printf("\r\n");
} }
); );
*/ */
@ -153,4 +136,3 @@ void loop(void) {
webServer.handleClient(); webServer.handleClient();
MDNS.update(); MDNS.update();
} }

View File

@ -23,7 +23,6 @@
#include <lwip/init.h> #include <lwip/init.h>
#include "Schedule.h" #include "Schedule.h"
namespace NetCapture namespace NetCapture
{ {
@ -69,24 +68,26 @@ void Netdump::reset()
void Netdump::printDump(Print& out, Packet::PacketDetail ndd, const Filter nf) void Netdump::printDump(Print& out, Packet::PacketDetail ndd, const Filter nf)
{ {
out.printf_P(PSTR("netDump starting\r\n")); out.printf_P(PSTR("netDump starting\r\n"));
setCallback([&out, ndd, this](const Packet & ndp) setCallback(
{ [&out, ndd, this](const Packet& ndp)
printDumpProcess(out, ndd, ndp); {
}, nf); printDumpProcess(out, ndd, ndp);
},
nf);
} }
void Netdump::fileDump(File& outfile, const Filter nf) void Netdump::fileDump(File& outfile, const Filter nf)
{ {
writePcapHeader(outfile); writePcapHeader(outfile);
setCallback([&outfile, this](const Packet & ndp) setCallback(
{ [&outfile, this](const Packet& ndp)
fileDumpProcess(outfile, ndp); {
}, nf); fileDumpProcess(outfile, ndp);
},
nf);
} }
bool Netdump::tcpDump(WiFiServer &tcpDumpServer, const Filter nf) bool Netdump::tcpDump(WiFiServer& tcpDumpServer, const Filter nf)
{ {
if (!packetBuffer) if (!packetBuffer)
{ {
packetBuffer = new (std::nothrow) char[tcpBufferSize]; packetBuffer = new (std::nothrow) char[tcpBufferSize];
@ -98,10 +99,11 @@ bool Netdump::tcpDump(WiFiServer &tcpDumpServer, const Filter nf)
} }
bufferIndex = 0; bufferIndex = 0;
schedule_function([&tcpDumpServer, this, nf]() schedule_function(
{ [&tcpDumpServer, this, nf]()
tcpDumpLoop(tcpDumpServer, nf); {
}); tcpDumpLoop(tcpDumpServer, nf);
});
return true; return true;
} }
@ -109,7 +111,8 @@ void Netdump::capture(int netif_idx, const char* data, size_t len, int out, int
{ {
if (lwipCallback.execute(netif_idx, data, len, out, success) == 0) if (lwipCallback.execute(netif_idx, data, len, out, success) == 0)
{ {
phy_capture = nullptr; // No active callback/netdump instances, will be set again by new object. phy_capture
= nullptr; // No active callback/netdump instances, will be set again by new object.
} }
} }
@ -118,7 +121,7 @@ void Netdump::netdumpCapture(int netif_idx, const char* data, size_t len, int ou
if (netDumpCallback) if (netDumpCallback)
{ {
Packet np(millis(), netif_idx, data, len, out, success); Packet np(millis(), netif_idx, data, len, out, success);
if (netDumpFilter && !netDumpFilter(np)) if (netDumpFilter && !netDumpFilter(np))
{ {
return; return;
} }
@ -131,8 +134,8 @@ void Netdump::writePcapHeader(Stream& s) const
uint32_t pcapHeader[6]; uint32_t pcapHeader[6];
pcapHeader[0] = 0xa1b2c3d4; // pcap magic number pcapHeader[0] = 0xa1b2c3d4; // pcap magic number
pcapHeader[1] = 0x00040002; // pcap major/minor version pcapHeader[1] = 0x00040002; // pcap major/minor version
pcapHeader[2] = 0; // pcap UTC correction in seconds pcapHeader[2] = 0; // pcap UTC correction in seconds
pcapHeader[3] = 0; // pcap time stamp accuracy pcapHeader[3] = 0; // pcap time stamp accuracy
pcapHeader[4] = maxPcapLength; // pcap max packet length per record pcapHeader[4] = maxPcapLength; // pcap max packet length per record
pcapHeader[5] = 1; // pacp data linkt type = ethernet pcapHeader[5] = 1; // pacp data linkt type = ethernet
s.write(reinterpret_cast<char*>(pcapHeader), 24); s.write(reinterpret_cast<char*>(pcapHeader), 24);
@ -145,7 +148,7 @@ void Netdump::printDumpProcess(Print& out, Packet::PacketDetail ndd, const Packe
void Netdump::fileDumpProcess(File& outfile, const Packet& np) const void Netdump::fileDumpProcess(File& outfile, const Packet& np) const
{ {
size_t incl_len = np.getPacketSize() > maxPcapLength ? maxPcapLength : np.getPacketSize(); size_t incl_len = np.getPacketSize() > maxPcapLength ? maxPcapLength : np.getPacketSize();
uint32_t pcapHeader[4]; uint32_t pcapHeader[4];
struct timeval tv; struct timeval tv;
@ -154,7 +157,7 @@ void Netdump::fileDumpProcess(File& outfile, const Packet& np) const
pcapHeader[1] = tv.tv_usec; pcapHeader[1] = tv.tv_usec;
pcapHeader[2] = incl_len; pcapHeader[2] = incl_len;
pcapHeader[3] = np.getPacketSize(); pcapHeader[3] = np.getPacketSize();
outfile.write(reinterpret_cast<char*>(pcapHeader), 16); // pcap record header outfile.write(reinterpret_cast<char*>(pcapHeader), 16); // pcap record header
outfile.write(np.rawData(), incl_len); outfile.write(np.rawData(), incl_len);
} }
@ -168,16 +171,16 @@ void Netdump::tcpDumpProcess(const Packet& np)
} }
size_t incl_len = np.getPacketSize() > maxPcapLength ? maxPcapLength : np.getPacketSize(); size_t incl_len = np.getPacketSize() > maxPcapLength ? maxPcapLength : np.getPacketSize();
if (bufferIndex + 16 + incl_len < tcpBufferSize) // only add if enough space available if (bufferIndex + 16 + incl_len < tcpBufferSize) // only add if enough space available
{ {
struct timeval tv; struct timeval tv;
gettimeofday(&tv, nullptr); gettimeofday(&tv, nullptr);
uint32_t* pcapHeader = reinterpret_cast<uint32_t*>(&packetBuffer[bufferIndex]); uint32_t* pcapHeader = reinterpret_cast<uint32_t*>(&packetBuffer[bufferIndex]);
pcapHeader[0] = tv.tv_sec; // add pcap record header pcapHeader[0] = tv.tv_sec; // add pcap record header
pcapHeader[1] = tv.tv_usec; pcapHeader[1] = tv.tv_usec;
pcapHeader[2] = incl_len; pcapHeader[2] = incl_len;
pcapHeader[3] = np.getPacketSize(); pcapHeader[3] = np.getPacketSize();
bufferIndex += 16; // pcap header size bufferIndex += 16; // pcap header size
memcpy(&packetBuffer[bufferIndex], np.rawData(), incl_len); memcpy(&packetBuffer[bufferIndex], np.rawData(), incl_len);
bufferIndex += incl_len; bufferIndex += incl_len;
} }
@ -189,7 +192,7 @@ void Netdump::tcpDumpProcess(const Packet& np)
} }
} }
void Netdump::tcpDumpLoop(WiFiServer &tcpDumpServer, const Filter nf) void Netdump::tcpDumpLoop(WiFiServer& tcpDumpServer, const Filter nf)
{ {
if (tcpDumpServer.hasClient()) if (tcpDumpServer.hasClient())
{ {
@ -199,10 +202,12 @@ void Netdump::tcpDumpLoop(WiFiServer &tcpDumpServer, const Filter nf)
bufferIndex = 0; bufferIndex = 0;
writePcapHeader(tcpDumpClient); writePcapHeader(tcpDumpClient);
setCallback([this](const Packet & ndp) setCallback(
{ [this](const Packet& ndp)
tcpDumpProcess(ndp); {
}, nf); tcpDumpProcess(ndp);
},
nf);
} }
if (!tcpDumpClient || !tcpDumpClient.connected()) if (!tcpDumpClient || !tcpDumpClient.connected())
{ {
@ -216,11 +221,12 @@ void Netdump::tcpDumpLoop(WiFiServer &tcpDumpServer, const Filter nf)
if (tcpDumpServer.status() != CLOSED) if (tcpDumpServer.status() != CLOSED)
{ {
schedule_function([&tcpDumpServer, this, nf]() schedule_function(
{ [&tcpDumpServer, this, nf]()
tcpDumpLoop(tcpDumpServer, nf); {
}); tcpDumpLoop(tcpDumpServer, nf);
});
} }
} }
} // namespace NetCapture } // namespace NetCapture

View File

@ -38,9 +38,8 @@ using namespace experimental::CBListImplentation;
class Netdump class Netdump
{ {
public: public:
using Filter = std::function<bool(const Packet&)>;
using Filter = std::function<bool(const Packet&)>; using Callback = std::function<void(const Packet&)>;
using Callback = std::function<void(const Packet&)>;
using LwipCallback = std::function<void(int, const char*, int, int, int)>; using LwipCallback = std::function<void(int, const char*, int, int, int)>;
Netdump(); Netdump();
@ -53,15 +52,14 @@ public:
void printDump(Print& out, Packet::PacketDetail ndd, const Filter nf = nullptr); void printDump(Print& out, Packet::PacketDetail ndd, const Filter nf = nullptr);
void fileDump(File& outfile, const Filter nf = nullptr); void fileDump(File& outfile, const Filter nf = nullptr);
bool tcpDump(WiFiServer &tcpDumpServer, const Filter nf = nullptr); bool tcpDump(WiFiServer& tcpDumpServer, const Filter nf = nullptr);
private: private:
Callback netDumpCallback = nullptr; Callback netDumpCallback = nullptr;
Filter netDumpFilter = nullptr; Filter netDumpFilter = nullptr;
static void capture(int netif_idx, const char* data, size_t len, int out, int success); static void capture(int netif_idx, const char* data, size_t len, int out, int success);
static CallBackList<LwipCallback> lwipCallback; static CallBackList<LwipCallback> lwipCallback;
CallBackList<LwipCallback>::CallBackHandler lwipHandler; CallBackList<LwipCallback>::CallBackHandler lwipHandler;
void netdumpCapture(int netif_idx, const char* data, size_t len, int out, int success); void netdumpCapture(int netif_idx, const char* data, size_t len, int out, int success);
@ -69,19 +67,19 @@ private:
void printDumpProcess(Print& out, Packet::PacketDetail ndd, const Packet& np) const; void printDumpProcess(Print& out, Packet::PacketDetail ndd, const Packet& np) const;
void fileDumpProcess(File& outfile, const Packet& np) const; void fileDumpProcess(File& outfile, const Packet& np) const;
void tcpDumpProcess(const Packet& np); void tcpDumpProcess(const Packet& np);
void tcpDumpLoop(WiFiServer &tcpDumpServer, const Filter nf); void tcpDumpLoop(WiFiServer& tcpDumpServer, const Filter nf);
void writePcapHeader(Stream& s) const; void writePcapHeader(Stream& s) const;
WiFiClient tcpDumpClient; WiFiClient tcpDumpClient;
char* packetBuffer = nullptr; char* packetBuffer = nullptr;
int bufferIndex = 0; int bufferIndex = 0;
static constexpr int tcpBufferSize = 2048; static constexpr int tcpBufferSize = 2048;
static constexpr int maxPcapLength = 1024; static constexpr int maxPcapLength = 1024;
static constexpr uint32_t pcapMagic = 0xa1b2c3d4; static constexpr uint32_t pcapMagic = 0xa1b2c3d4;
}; };
} // namespace NetCapture } // namespace NetCapture
#endif /* __NETDUMP_H */ #endif /* __NETDUMP_H */

Some files were not shown because too many files have changed in this diff Show More