2020-06-15 17:27:04 +01:00
/*
2021-01-27 09:38:45 +00:00
xdrv_82_esp32_ethernet . ino - ESP32 ( PoE ) ethernet support for Tasmota
2020-06-15 17:27:04 +01:00
2021-01-01 12:44:04 +00:00
Copyright ( C ) 2021 Theo Arends
2020-06-15 17:27:04 +01:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# ifdef ESP32
2021-02-02 16:55:45 +00:00
# if CONFIG_IDF_TARGET_ESP32
2020-06-15 17:27:04 +01:00
# ifdef USE_ETHERNET
/*********************************************************************************************\
* Ethernet support for ESP32
2020-06-16 17:36:49 +01:00
*
* Dedicated fixed Phy pins
* GPIO17 - EMAC_CLK_OUT_180
* GPIO19 - EMAC_TXD0 ( RMII )
* GPIO21 - EMAC_TX_EN ( RMII )
* GPIO22 - EMAC_TXD1 ( RMII )
* GPIO25 - EMAC_RXD0 ( RMII )
* GPIO26 - EMAC_RXD1 ( RMII )
* GPIO27 - EMAC_RX_CRS_DV
*
2020-06-18 11:55:10 +01:00
* { " NAME " : " Olimex ESP32-PoE " , " GPIO " : [ 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 5536 , 1 , 1 , 1 , 1 , 0 , 5600 , 0 , 0 , 0 , 0 , 5568 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 ] , " FLAG " : 0 , " BASE " : 1 }
2020-10-23 14:18:58 +01:00
* GPIO12 = ETH POWER
* GPIO18 = ETH MDIO
* GPIO23 = ETH MDC
* # define ETH_TYPE ETH_PHY_LAN8720
* # define ETH_CLKMODE ETH_CLOCK_GPIO17_OUT
2021-02-02 17:02:24 +00:00
* # define ETH_ADDRESS 0
2020-10-23 14:18:58 +01:00
*
2020-06-20 11:00:40 +01:00
* { " NAME " : " wESP32 " , " GPIO " : [ 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 5568 , 5600 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 ] , " FLAG " : 0 , " BASE " : 1 }
2020-10-23 14:18:58 +01:00
* GPIO16 = ETH MDC
* GPIO17 = ETH MDIO
* # define ETH_TYPE ETH_PHY_LAN8720
* # define ETH_CLKMODE ETH_CLOCK_GPIO0_IN
2021-02-02 17:02:24 +00:00
* # define ETH_ADDRESS 0
2020-10-23 14:18:58 +01:00
*
* { " NAME " : " WT32-ETH01 " , " GPIO " : [ 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 3840 , 576 , 5600 , 0 , 0 , 0 , 0 , 5568 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 1 , 1 , 0 , 0 , 1 ] , " FLAG " : 0 , " BASE " : 1 }
* GPIO16 = Force Hi
* GPIO18 = ETH MDIO
* GPIO23 = ETH MDC
* # define ETH_TYPE ETH_PHY_LAN8720
* # define ETH_CLKMODE ETH_CLOCK_GPIO0_IN
2021-02-02 17:02:24 +00:00
* # define ETH_ADDRESS 1
2020-10-23 14:18:58 +01:00
*
2020-06-15 17:27:04 +01:00
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define XDRV_82 82
2020-06-16 17:36:49 +01:00
/*
2020-06-15 17:27:04 +01:00
// Olimex ESP32-PoE
2020-06-16 17:36:49 +01:00
# define ETH_CLKMODE ETH_CLOCK_GPIO17_OUT
# define ETH_POWER_PIN 12
//********************************************************************************************
2021-02-02 17:02:24 +00:00
# ifndef ETH_ADDRESS
2021-07-04 13:53:58 +01:00
# define ETH_ADDRESS 0 // ETH.h uint8_t: 0 = PHY0 .. 31 = PHY31
2020-06-16 17:36:49 +01:00
# endif
# ifndef ETH_TYPE
2021-07-04 13:53:58 +01:00
# define ETH_TYPE ETH_PHY_LAN8720 // ETH.h eth_phy_type_t: 0 = ETH_PHY_LAN8720, 1 = ETH_PHY_TLK110/ETH_PHY_IP101, 2 = ETH_PHY_RTL8201, 3 = ETH_PHY_DP83848, 4 = ETH_PHY_DM9051, 5 = ETH_PHY_KSZ8081
2020-06-16 17:36:49 +01:00
# endif
# ifndef ETH_CLKMODE
2021-07-04 13:53:58 +01:00
# define ETH_CLKMODE ETH_CLOCK_GPIO0_IN // ETH.h eth_clock_mode_t: 0 = ETH_CLOCK_GPIO0_IN, 1 = ETH_CLOCK_GPIO0_OUT, 2 = ETH_CLOCK_GPIO16_OUT, 3 = ETH_CLOCK_GPIO17_OUT
2020-06-16 17:36:49 +01:00
# endif
*/
2020-06-15 17:27:04 +01:00
# include <ETH.h>
2020-10-30 11:29:48 +00:00
char eth_hostname [ sizeof ( TasmotaGlobal . hostname ) ] ;
2022-01-12 16:32:21 +00:00
uint8_t eth_config_change ;
2020-06-15 17:27:04 +01:00
void EthernetEvent ( WiFiEvent_t event ) {
switch ( event ) {
2021-11-21 12:30:05 +00:00
case ARDUINO_EVENT_ETH_START :
2021-01-23 16:10:06 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ETH: " D_ATTEMPTING_CONNECTION ) ) ;
2020-06-18 16:47:29 +01:00
ETH . setHostname ( eth_hostname ) ;
2020-06-15 17:27:04 +01:00
break ;
2021-11-21 12:30:05 +00:00
case ARDUINO_EVENT_ETH_CONNECTED :
2021-01-23 16:10:06 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( " ETH: " D_CONNECTED " at %dMbps%s " ) ,
2020-10-23 14:18:58 +01:00
ETH . linkSpeed ( ) , ( ETH . fullDuplex ( ) ) ? " Full Duplex " : " " ) ;
2020-06-15 17:27:04 +01:00
break ;
2021-11-21 12:30:05 +00:00
case ARDUINO_EVENT_ETH_GOT_IP :
2021-01-27 11:14:33 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ETH: Mac %s, IPAddress %_I, Hostname %s " ) ,
ETH . macAddress ( ) . c_str ( ) , ( uint32_t ) ETH . localIP ( ) , eth_hostname ) ;
2022-01-12 16:32:21 +00:00
Settings - > eth_ipv4_address [ 1 ] = ( uint32_t ) ETH . gatewayIP ( ) ;
Settings - > eth_ipv4_address [ 2 ] = ( uint32_t ) ETH . subnetMask ( ) ;
Settings - > eth_ipv4_address [ 3 ] = ( uint32_t ) ETH . dnsIP ( ) ;
Settings - > eth_ipv4_address [ 4 ] = ( uint32_t ) ETH . dnsIP ( 1 ) ;
TasmotaGlobal . rules_flag . eth_connected = 1 ;
2020-10-30 11:29:48 +00:00
TasmotaGlobal . global_state . eth_down = 0 ;
2020-06-15 17:27:04 +01:00
break ;
2021-11-21 12:30:05 +00:00
case ARDUINO_EVENT_ETH_DISCONNECTED :
2021-01-23 16:10:06 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( " ETH: Disconnected " ) ) ;
2022-01-12 16:32:21 +00:00
TasmotaGlobal . rules_flag . eth_disconnected = 1 ;
2020-10-30 11:29:48 +00:00
TasmotaGlobal . global_state . eth_down = 1 ;
2020-06-15 17:27:04 +01:00
break ;
2021-11-21 12:30:05 +00:00
case ARDUINO_EVENT_ETH_STOP :
2021-01-23 16:10:06 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ETH: Stopped " ) ) ;
2020-10-30 11:29:48 +00:00
TasmotaGlobal . global_state . eth_down = 1 ;
2020-06-15 17:27:04 +01:00
break ;
default :
break ;
}
}
2022-01-12 16:32:21 +00:00
void EthernetSetIp ( void ) {
// IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2
ETH . config ( Settings - > eth_ipv4_address [ 0 ] , Settings - > eth_ipv4_address [ 1 ] , Settings - > eth_ipv4_address [ 2 ] , Settings - > eth_ipv4_address [ 3 ] , Settings - > eth_ipv4_address [ 4 ] ) ; // Set static IP
}
2020-06-15 17:27:04 +01:00
void EthernetInit ( void ) {
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag4 . network_ethernet ) { return ; }
2020-06-17 17:31:31 +01:00
if ( ! PinUsed ( GPIO_ETH_PHY_MDC ) & & ! PinUsed ( GPIO_ETH_PHY_MDIO ) ) {
2021-01-23 16:10:06 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ETH: No ETH MDC and/or ETH MDIO GPIO defined " ) ) ;
2020-06-17 17:31:31 +01:00
return ;
}
2020-06-15 17:27:04 +01:00
2022-01-12 16:32:21 +00:00
eth_config_change = 0 ;
2021-01-27 13:27:05 +00:00
if ( WT32_ETH01 = = TasmotaGlobal . module_type ) {
2021-06-11 17:14:12 +01:00
Settings - > eth_address = 1 ; // EthAddress
Settings - > eth_type = ETH_PHY_LAN8720 ; // EthType
Settings - > eth_clk_mode = ETH_CLOCK_GPIO0_IN ; // EthClockMode
2021-01-27 13:27:05 +00:00
}
2021-11-21 12:30:05 +00:00
// snprintf_P(Eth.hostname, sizeof(Eth.hostname), PSTR("%s-eth"), TasmotaGlobal.hostname);
strlcpy ( eth_hostname , TasmotaGlobal . hostname , sizeof ( eth_hostname ) - 5 ) ; // Make sure there is room for "-eth"
strcat ( eth_hostname , " -eth " ) ;
2020-06-18 16:47:29 +01:00
2020-06-15 17:27:04 +01:00
WiFi . onEvent ( EthernetEvent ) ;
2020-06-16 17:36:49 +01:00
2021-02-14 12:06:19 +00:00
int eth_power = Pin ( GPIO_ETH_PHY_POWER ) ;
2020-06-17 17:31:31 +01:00
int eth_mdc = Pin ( GPIO_ETH_PHY_MDC ) ;
int eth_mdio = Pin ( GPIO_ETH_PHY_MDIO ) ;
2021-06-11 17:14:12 +01:00
if ( ! ETH . begin ( Settings - > eth_address , eth_power , eth_mdc , eth_mdio , ( eth_phy_type_t ) Settings - > eth_type , ( eth_clock_mode_t ) Settings - > eth_clk_mode ) ) {
2021-01-23 16:10:06 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ETH: Bad PHY type or init error " ) ) ;
2022-01-12 16:32:21 +00:00
return ;
2020-06-16 17:36:49 +01:00
} ;
2022-01-12 16:32:21 +00:00
if ( Settings - > eth_ipv4_address [ 0 ] ) {
EthernetSetIp ( ) ; // Set static IP
}
2020-06-15 17:27:04 +01:00
}
IPAddress EthernetLocalIP ( void ) {
return ETH . localIP ( ) ;
}
char * EthernetHostname ( void ) {
2020-06-18 16:47:29 +01:00
return eth_hostname ;
2020-06-15 17:27:04 +01:00
}
String EthernetMacAddress ( void ) {
return ETH . macAddress ( ) ;
}
2022-01-12 16:32:21 +00:00
void EthernetConfigChange ( void ) {
if ( eth_config_change ) {
eth_config_change - - ;
if ( ! eth_config_change ) {
EthernetSetIp ( ) ;
}
}
}
2020-06-15 17:27:04 +01:00
/*********************************************************************************************\
* Commands
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-01-12 16:32:21 +00:00
# define D_CMND_ETHADDRESS "Address"
# define D_CMND_ETHTYPE "Type"
# define D_CMND_ETHCLOCKMODE "ClockMode"
# define D_CMND_ETHIPADDRESS D_CMND_IPADDRESS
# define D_CMND_ETHGATEWAY D_JSON_GATEWAY
# define D_CMND_ETHNETMASK D_JSON_SUBNETMASK
# define D_CMND_ETHDNS D_JSON_DNSSERVER
2020-06-16 17:36:49 +01:00
2022-01-12 16:32:21 +00:00
const char kEthernetCommands [ ] PROGMEM = " Eth| " // Prefix
" ernet| " D_CMND_ETHADDRESS " | " D_CMND_ETHTYPE " | " D_CMND_ETHCLOCKMODE " | "
2022-01-13 14:27:24 +00:00
D_CMND_ETHIPADDRESS " | " D_CMND_ETHGATEWAY " | " D_CMND_ETHNETMASK " | " D_CMND_ETHDNS ;
2020-06-15 17:27:04 +01:00
void ( * const EthernetCommand [ ] ) ( void ) PROGMEM = {
2022-01-12 16:32:21 +00:00
& CmndEthernet , & CmndEthAddress , & CmndEthType , & CmndEthClockMode ,
2022-01-13 14:27:24 +00:00
& CmndEthSetIpConfig , & CmndEthSetIpConfig , & CmndEthSetIpConfig , & CmndEthSetIpConfig } ;
2020-06-15 17:27:04 +01:00
2022-01-12 16:32:21 +00:00
# define ETH_PARAM_OFFSET 4 // Offset of command index in above table of first CmndEthIpConfig
void CmndEthernet ( void ) {
2020-06-15 17:27:04 +01:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 1 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > flag4 . network_ethernet = XdrvMailbox . payload ;
2020-10-29 11:21:24 +00:00
TasmotaGlobal . restart_flag = 2 ;
2020-06-15 17:27:04 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndStateText ( Settings - > flag4 . network_ethernet ) ;
2020-06-15 17:27:04 +01:00
}
2022-01-12 16:32:21 +00:00
void CmndEthAddress ( void ) {
2020-06-16 17:36:49 +01:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 31 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > eth_address = XdrvMailbox . payload ;
2020-10-29 11:21:24 +00:00
TasmotaGlobal . restart_flag = 2 ;
2020-06-16 17:36:49 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > eth_address ) ;
2020-06-16 17:36:49 +01:00
}
2022-01-12 16:32:21 +00:00
void CmndEthType ( void ) {
2020-06-17 17:14:50 +01:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 2 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > eth_type = XdrvMailbox . payload ;
2020-10-29 11:21:24 +00:00
TasmotaGlobal . restart_flag = 2 ;
2020-06-16 17:36:49 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > eth_type ) ;
2020-06-16 17:36:49 +01:00
}
2022-01-12 16:32:21 +00:00
void CmndEthClockMode ( void ) {
2020-06-16 17:36:49 +01:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 3 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > eth_clk_mode = XdrvMailbox . payload ;
2020-10-29 11:21:24 +00:00
TasmotaGlobal . restart_flag = 2 ;
2020-06-16 17:36:49 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > eth_clk_mode ) ;
2020-06-16 17:36:49 +01:00
}
2022-01-12 16:32:21 +00:00
void CmndEthSetIpConfig ( void ) {
uint32_t param_id = XdrvMailbox . command_code - ETH_PARAM_OFFSET ;
char cmnd_idx [ 2 ] = { 0 } ;
if ( 3 = = param_id ) { // EthDnsServer
if ( ( XdrvMailbox . index < 1 ) | | ( XdrvMailbox . index > 2 ) ) {
XdrvMailbox . index = 1 ;
}
cmnd_idx [ 0 ] = ' 0 ' + XdrvMailbox . index ;
param_id + = XdrvMailbox . index - 1 ; // EthDnsServer2
}
if ( XdrvMailbox . data_len ) {
uint32_t ipv4_address ;
if ( ParseIPv4 ( & ipv4_address , XdrvMailbox . data ) ) {
Settings - > eth_ipv4_address [ param_id ] = ipv4_address ;
eth_config_change = 2 ;
}
}
char network_address [ 22 ] = { 0 } ;
if ( 0 = = param_id ) {
if ( ! Settings - > eth_ipv4_address [ 0 ] ) {
ext_snprintf_P ( network_address , sizeof ( network_address ) , PSTR ( " (%_I) " ) , ( uint32_t ) ETH . localIP ( ) ) ;
}
}
Response_P ( PSTR ( " { \" %s%s \" : \" %_I%s \" } " ) , XdrvMailbox . command , cmnd_idx , Settings - > eth_ipv4_address [ param_id ] , network_address ) ;
}
2020-06-15 17:27:04 +01:00
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool Xdrv82 ( uint8_t function ) {
bool result = false ;
switch ( function ) {
2022-01-12 16:32:21 +00:00
case FUNC_EVERY_SECOND :
EthernetConfigChange ( ) ;
break ;
2020-06-15 17:27:04 +01:00
case FUNC_COMMAND :
result = DecodeCommand ( kEthernetCommands , EthernetCommand ) ;
break ;
case FUNC_INIT :
EthernetInit ( ) ;
break ;
}
return result ;
}
# endif // USE_ETHERNET
2021-02-02 16:55:45 +00:00
# endif // CONFIG_IDF_TARGET_ESP32
2020-06-15 17:27:04 +01:00
# endif // ESP32