mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-29 05:21:37 +03:00
more lwIP physical interfaces (#6680)
This commit adds W5500 W5100 and ENC28j60 drivers from @njh with credits They are available in libraries/ An example is added in W5500 examples directory plus: * Extract dhcp server from lwip2 and add it to the core as a class. It must always be present, it is linked and can be called by fw on boot. So it cannot be stored in a library. * ethernet: static or dhcp works * PPPServer: example * bring WiFi.config() to the lwIP generic interface (argument reorder common function) * move hostname() from WiFI-STA to generic interface * remove non readable characters from dhcp-server comments * dhcp-server: magic_cookie is part of bootp rfc * fixes from https://github.com/d-a-v/W5500lwIP/issues/17 * enable lwip_hook_dhcp_parse_option() * +ethernet tcp client example in w5500 library examples
This commit is contained in:
@ -13,7 +13,7 @@
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <lwip/napt.h>
|
||||
#include <lwip/dns.h>
|
||||
#include <dhcpserver.h>
|
||||
#include <LwipDhcpServer.h>
|
||||
|
||||
#define NAPT 1000
|
||||
#define NAPT_PORT 10
|
||||
@ -57,8 +57,8 @@ void setup() {
|
||||
WiFi.dnsIP(1).toString().c_str());
|
||||
|
||||
// give DNS servers to AP side
|
||||
dhcps_set_dns(0, WiFi.dnsIP(0));
|
||||
dhcps_set_dns(1, WiFi.dnsIP(1));
|
||||
dhcpSoftAP.dhcps_set_dns(0, WiFi.dnsIP(0));
|
||||
dhcpSoftAP.dhcps_set_dns(1, WiFi.dnsIP(1));
|
||||
|
||||
WiFi.softAPConfig( // enable AP, with android-compatible google domain
|
||||
IPAddress(172, 217, 28, 254),
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <LwipDhcpServer.h>
|
||||
|
||||
/* Set these to your desired credentials. */
|
||||
const char *ssid = "ESPap";
|
||||
@ -75,8 +76,8 @@ void setup() {
|
||||
...
|
||||
any client not listed will use next IP address available from the range (here 192.168.0.102 and more)
|
||||
*/
|
||||
wifi_softap_add_dhcps_lease(mac_CAM); // always 192.168.0.100
|
||||
wifi_softap_add_dhcps_lease(mac_PC); // always 192.168.0.101
|
||||
dhcpSoftAP.add_dhcps_lease(mac_CAM); // always 192.168.0.100
|
||||
dhcpSoftAP.add_dhcps_lease(mac_PC); // always 192.168.0.101
|
||||
/* Start Access Point. You can remove the password parameter if you want the AP to be open. */
|
||||
WiFi.softAP(ssid, password);
|
||||
Serial.print("AP IP address: ");
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" {
|
||||
#include "include/wl_definitions.h"
|
||||
#include <wl_definitions.h>
|
||||
}
|
||||
|
||||
#include "IPAddress.h"
|
||||
|
@ -33,11 +33,11 @@ extern "C" {
|
||||
#include "osapi.h"
|
||||
#include "mem.h"
|
||||
#include "user_interface.h"
|
||||
#include <lwip/init.h> // LWIP_VERSION_*
|
||||
}
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#include "LwipDhcpServer.h"
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------- Private functions ------------------------------------------------
|
||||
@ -156,13 +156,7 @@ bool ESP8266WiFiAPClass::softAP(const char* ssid, const char* passphrase, int ch
|
||||
DEBUG_WIFI("[AP] softap config unchanged\n");
|
||||
}
|
||||
|
||||
if(wifi_softap_dhcps_status() != DHCP_STARTED) {
|
||||
DEBUG_WIFI("[AP] DHCP not started, starting...\n");
|
||||
if(!wifi_softap_dhcps_start()) {
|
||||
DEBUG_WIFI("[AP] wifi_softap_dhcps_start failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
dhcpSoftAP.end();
|
||||
|
||||
// check IP config
|
||||
struct ip_info ip;
|
||||
@ -182,6 +176,8 @@ bool ESP8266WiFiAPClass::softAP(const char* ssid, const char* passphrase, int ch
|
||||
ret = false;
|
||||
}
|
||||
|
||||
dhcpSoftAP.begin(&ip);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -237,19 +233,22 @@ bool ESP8266WiFiAPClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPA
|
||||
dhcp_lease.end_ip.addr = ip.v4();
|
||||
DEBUG_WIFI("[APConfig] DHCP IP end: %s\n", ip.toString().c_str());
|
||||
|
||||
if(!wifi_softap_set_dhcps_lease(&dhcp_lease)) {
|
||||
if(!dhcpSoftAP.set_dhcps_lease(&dhcp_lease))
|
||||
{
|
||||
DEBUG_WIFI("[APConfig] wifi_set_ip_info failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
// set lease time to 720min --> 12h
|
||||
if(!wifi_softap_set_dhcps_lease_time(720)) {
|
||||
if(!dhcpSoftAP.set_dhcps_lease_time(720))
|
||||
{
|
||||
DEBUG_WIFI("[APConfig] wifi_softap_set_dhcps_lease_time failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
uint8 mode = info.gw.addr ? 1 : 0;
|
||||
if(!wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &mode)) {
|
||||
if(!dhcpSoftAP.set_dhcps_offer_option(OFFER_ROUTER, &mode))
|
||||
{
|
||||
DEBUG_WIFI("[APConfig] wifi_softap_set_dhcps_offer_option failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
#include "ESP8266WiFiSTA.h"
|
||||
#include "PolledTimeout.h"
|
||||
#include "LwipIntf.h"
|
||||
|
||||
#include "c_types.h"
|
||||
#include "ets_sys.h"
|
||||
@ -281,28 +282,9 @@ bool ESP8266WiFiSTAClass::config(IPAddress local_ip, IPAddress arg1, IPAddress a
|
||||
return true;
|
||||
}
|
||||
|
||||
//To allow compatibility, check first octet of 3rd arg. If 255, interpret as ESP order, otherwise Arduino order.
|
||||
IPAddress gateway = arg1;
|
||||
IPAddress subnet = arg2;
|
||||
IPAddress dns1 = arg3;
|
||||
|
||||
if(subnet[0] != 255)
|
||||
{
|
||||
//octet is not 255 => interpret as Arduino order
|
||||
gateway = arg2;
|
||||
subnet = arg3[0] == 0 ? IPAddress(255,255,255,0) : arg3; //arg order is arduino and 4th arg not given => assign it arduino default
|
||||
dns1 = arg1;
|
||||
}
|
||||
|
||||
// check whether all is IPv4 (or gateway not set)
|
||||
if (!(local_ip.isV4() && subnet.isV4() && (!gateway.isSet() || gateway.isV4()))) {
|
||||
IPAddress gateway, subnet, dns1;
|
||||
if (!ipAddressReorder(local_ip, arg1, arg2, arg3, gateway, subnet, dns1))
|
||||
return false;
|
||||
}
|
||||
|
||||
//ip and gateway must be in the same subnet
|
||||
if((local_ip.v4() & subnet.v4()) != (gateway.v4() & subnet.v4())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !CORE_MOCK
|
||||
// get current->previous IP address
|
||||
@ -522,94 +504,6 @@ IPAddress ESP8266WiFiSTAClass::dnsIP(uint8_t dns_no) {
|
||||
return IPAddress(dns_getserver(dns_no));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get ESP8266 station DHCP hostname
|
||||
* @return hostname
|
||||
*/
|
||||
String ESP8266WiFiSTAClass::hostname(void) {
|
||||
return wifi_station_get_hostname();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ESP8266 station DHCP hostname
|
||||
* @param aHostname max length:24
|
||||
* @return ok
|
||||
*/
|
||||
bool ESP8266WiFiSTAClass::hostname(const char* aHostname) {
|
||||
/*
|
||||
vvvv RFC952 vvvv
|
||||
ASSUMPTIONS
|
||||
1. A "name" (Net, Host, Gateway, or Domain name) is a text string up
|
||||
to 24 characters drawn from the alphabet (A-Z), digits (0-9), minus
|
||||
sign (-), and period (.). Note that periods are only allowed when
|
||||
they serve to delimit components of "domain style names". (See
|
||||
RFC-921, "Domain Name System Implementation Schedule", for
|
||||
background). No blank or space characters are permitted as part of a
|
||||
name. No distinction is made between upper and lower case. The first
|
||||
character must be an alpha character. The last character must not be
|
||||
a minus sign or period. A host which serves as a GATEWAY should have
|
||||
"-GATEWAY" or "-GW" as part of its name. Hosts which do not serve as
|
||||
Internet gateways should not use "-GATEWAY" and "-GW" as part of
|
||||
their names. A host which is a TAC should have "-TAC" as the last
|
||||
part of its host name, if it is a DoD host. Single character names
|
||||
or nicknames are not allowed.
|
||||
^^^^ RFC952 ^^^^
|
||||
|
||||
- 24 chars max
|
||||
- only a..z A..Z 0..9 '-'
|
||||
- no '-' as last char
|
||||
*/
|
||||
|
||||
size_t len = strlen(aHostname);
|
||||
|
||||
if (len == 0 || len > 32) {
|
||||
// nonos-sdk limit is 32
|
||||
// (dhcp hostname option minimum size is ~60)
|
||||
DEBUG_WIFI_GENERIC("WiFi.(set)hostname(): empty or large(>32) name\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// check RFC compliance
|
||||
bool compliant = (len <= 24);
|
||||
for (size_t i = 0; compliant && i < len; i++)
|
||||
if (!isalnum(aHostname[i]) && aHostname[i] != '-')
|
||||
compliant = false;
|
||||
if (aHostname[len - 1] == '-')
|
||||
compliant = false;
|
||||
|
||||
if (!compliant) {
|
||||
DEBUG_WIFI_GENERIC("hostname '%s' is not compliant with RFC952\n", aHostname);
|
||||
}
|
||||
|
||||
bool ret = wifi_station_set_hostname(aHostname);
|
||||
if (!ret) {
|
||||
DEBUG_WIFI_GENERIC("WiFi.hostname(%s): wifi_station_set_hostname() failed\n", aHostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
// now we should inform dhcp server for this change, using lwip_renew()
|
||||
// looping through all existing interface
|
||||
// harmless for AP, also compatible with ethernet adapters (to come)
|
||||
for (netif* intf = netif_list; intf; intf = intf->next) {
|
||||
|
||||
// unconditionally update all known interfaces
|
||||
intf->hostname = wifi_station_get_hostname();
|
||||
|
||||
if (netif_dhcp_data(intf) != nullptr) {
|
||||
// renew already started DHCP leases
|
||||
err_t lwipret = dhcp_renew(intf);
|
||||
if (lwipret != ERR_OK) {
|
||||
DEBUG_WIFI_GENERIC("WiFi.hostname(%s): lwIP error %d on interface %c%c (index %d)\n",
|
||||
intf->hostname, (int)lwipret, intf->name[0], intf->name[1], intf->num);
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret && compliant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Connection status.
|
||||
* @return one of the value defined in wl_status_t
|
||||
|
@ -27,9 +27,10 @@
|
||||
#include "ESP8266WiFiType.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
#include "user_interface.h"
|
||||
#include "LwipIntf.h"
|
||||
|
||||
|
||||
class ESP8266WiFiSTAClass {
|
||||
class ESP8266WiFiSTAClass: public LwipIntf {
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------- STA function ----------------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
@ -69,10 +70,6 @@ class ESP8266WiFiSTAClass {
|
||||
IPAddress gatewayIP();
|
||||
IPAddress dnsIP(uint8_t dns_no = 0);
|
||||
|
||||
String hostname();
|
||||
bool hostname(const String& aHostname) { return hostname(aHostname.c_str()); }
|
||||
bool hostname(const char* aHostname);
|
||||
|
||||
// STA WiFi info
|
||||
wl_status_t status();
|
||||
String SSID() const;
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "include/wl_definitions.h"
|
||||
#include "wl_definitions.h"
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
#define wifiserver_h
|
||||
|
||||
extern "C" {
|
||||
#include "include/wl_definitions.h"
|
||||
#include "wl_definitions.h"
|
||||
|
||||
struct tcp_pcb;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "include/wl_definitions.h"
|
||||
#include "wl_definitions.h"
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
}
|
||||
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
wl_definitions.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
/*
|
||||
* wl_definitions.h
|
||||
*
|
||||
* Created on: Mar 6, 2011
|
||||
* Author: dlafauci
|
||||
*/
|
||||
|
||||
#ifndef WL_DEFINITIONS_H_
|
||||
#define WL_DEFINITIONS_H_
|
||||
|
||||
// Maximum size of a SSID
|
||||
#define WL_SSID_MAX_LENGTH 32
|
||||
// Length of passphrase. Valid lengths are 8-63.
|
||||
#define WL_WPA_KEY_MAX_LENGTH 63
|
||||
// Length of key in bytes. Valid values are 5 and 13.
|
||||
#define WL_WEP_KEY_MAX_LENGTH 13
|
||||
// Size of a MAC-address or BSSID
|
||||
#define WL_MAC_ADDR_LENGTH 6
|
||||
// Size of a MAC-address or BSSID
|
||||
#define WL_IPV4_LENGTH 4
|
||||
// Maximum size of a SSID list
|
||||
#define WL_NETWORKS_LIST_MAXNUM 10
|
||||
// Maxmium number of socket
|
||||
#define MAX_SOCK_NUM 4
|
||||
// Socket not available constant
|
||||
#define SOCK_NOT_AVAIL 255
|
||||
// Default state value for Wifi state field
|
||||
#define NA_STATE -1
|
||||
//Maximum number of attempts to establish wifi connection
|
||||
#define WL_MAX_ATTEMPT_CONNECTION 10
|
||||
|
||||
typedef enum {
|
||||
WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library
|
||||
WL_IDLE_STATUS = 0,
|
||||
WL_NO_SSID_AVAIL = 1,
|
||||
WL_SCAN_COMPLETED = 2,
|
||||
WL_CONNECTED = 3,
|
||||
WL_CONNECT_FAILED = 4,
|
||||
WL_CONNECTION_LOST = 5,
|
||||
WL_WRONG_PASSWORD = 6,
|
||||
WL_DISCONNECTED = 7
|
||||
} wl_status_t;
|
||||
|
||||
/* Encryption modes */
|
||||
enum wl_enc_type { /* Values map to 802.11 encryption suites... */
|
||||
ENC_TYPE_WEP = 5,
|
||||
ENC_TYPE_TKIP = 2,
|
||||
ENC_TYPE_CCMP = 4,
|
||||
/* ... except these two, 7 and 8 are reserved in 802.11-2007 */
|
||||
ENC_TYPE_NONE = 7,
|
||||
ENC_TYPE_AUTO = 8
|
||||
};
|
||||
|
||||
#if !defined(LWIP_INTERNAL) && !defined(__LWIP_TCP_H__)
|
||||
enum wl_tcp_state {
|
||||
CLOSED = 0,
|
||||
LISTEN = 1,
|
||||
SYN_SENT = 2,
|
||||
SYN_RCVD = 3,
|
||||
ESTABLISHED = 4,
|
||||
FIN_WAIT_1 = 5,
|
||||
FIN_WAIT_2 = 6,
|
||||
CLOSE_WAIT = 7,
|
||||
CLOSING = 8,
|
||||
LAST_ACK = 9,
|
||||
TIME_WAIT = 10
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* WL_DEFINITIONS_H_ */
|
111
libraries/lwIP_PPP/examples/PPPServer/PPPServer.ino
Normal file
111
libraries/lwIP_PPP/examples/PPPServer/PPPServer.ino
Normal file
@ -0,0 +1,111 @@
|
||||
|
||||
// This is still beta / a work in progress
|
||||
|
||||
// To run this sketch an (other) USB-serial converter is needed connected to RX-TX ports (below)
|
||||
// hardware serial is used for logging
|
||||
// software serial is used for the PPP link
|
||||
// this example is subject for changes once everything is stabilized
|
||||
|
||||
// testing on linux:
|
||||
// sudo /usr/sbin/pppd /dev/ttyUSB1 38400 noipdefault nocrtscts local defaultroute noauth nodetach debug dump
|
||||
// sudo /usr/sbin/pppd /dev/ttyUSB1 38400 noipdefault nocrtscts local defaultroute noauth
|
||||
|
||||
// proxy arp is needed but we don't have it
|
||||
// http://lwip.100.n7.nabble.com/PPP-proxy-arp-support-tp33286p33345.html
|
||||
// using NAT instead
|
||||
|
||||
#if LWIP_FEATURES && !LWIP_IPV6
|
||||
|
||||
#include <lwip/napt.h>
|
||||
#include <lwip/dns.h>
|
||||
#include <PPPServer.h>
|
||||
#include <dhcpserver.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
#define LOGGERBAUD 115200
|
||||
#define PPPLINKBAUD 38400
|
||||
|
||||
#define NAPT 200
|
||||
#define NAPT_PORT 3
|
||||
|
||||
#define RX 13 // d1mini D7
|
||||
#define TX 15 // d1mini D8
|
||||
|
||||
SoftwareSerial ppplink(RX, TX);
|
||||
HardwareSerial& logger = Serial;
|
||||
PPPServer ppp(&ppplink);
|
||||
|
||||
void PPPConnectedCallback(netif* nif) {
|
||||
logger.printf("ppp: ip=%s/mask=%s/gw=%s\n",
|
||||
IPAddress(&nif->ip_addr).toString().c_str(),
|
||||
IPAddress(&nif->netmask).toString().c_str(),
|
||||
IPAddress(&nif->gw).toString().c_str());
|
||||
|
||||
logger.printf("Heap before: %d\n", ESP.getFreeHeap());
|
||||
err_t ret = ip_napt_init(NAPT, NAPT_PORT);
|
||||
logger.printf("ip_napt_init(%d,%d): ret=%d (OK=%d)\n", NAPT, NAPT_PORT, (int)ret, (int)ERR_OK);
|
||||
if (ret == ERR_OK) {
|
||||
ret = ip_napt_enable_no(nif->num, 1);
|
||||
logger.printf("ip_napt_enable(nif): ret=%d (OK=%d)\n", (int)ret, (int)ERR_OK);
|
||||
if (ret == ERR_OK) {
|
||||
logger.printf("PPP client is NATed\n");
|
||||
}
|
||||
|
||||
// could not make this work yet,
|
||||
// but packets are arriving on ppp client (= linux host)
|
||||
logger.printf("redirect22=%d\n", ip_portmap_add(IP_PROTO_TCP, ip_2_ip4(&nif->ip_addr)->addr, 22, ip_2_ip4(&nif->gw)->addr, 22));
|
||||
logger.printf("redirect80=%d\n", ip_portmap_add(IP_PROTO_TCP, ip_2_ip4(&nif->ip_addr)->addr, 80, ip_2_ip4(&nif->gw)->addr, 80));
|
||||
logger.printf("redirect443=%d\n", ip_portmap_add(IP_PROTO_TCP, ip_2_ip4(&nif->ip_addr)->addr, 443, ip_2_ip4(&nif->gw)->addr, 443));
|
||||
}
|
||||
logger.printf("Heap after napt init: %d\n", ESP.getFreeHeap());
|
||||
if (ret != ERR_OK) {
|
||||
logger.printf("NAPT initialization failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
logger.begin(LOGGERBAUD);
|
||||
|
||||
WiFi.persistent(false);
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(STASSID, STAPSK);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
logger.print('.');
|
||||
delay(500);
|
||||
}
|
||||
logger.printf("\nSTA: %s (dns: %s / %s)\n",
|
||||
WiFi.localIP().toString().c_str(),
|
||||
WiFi.dnsIP(0).toString().c_str(),
|
||||
WiFi.dnsIP(1).toString().c_str());
|
||||
|
||||
ppplink.begin(PPPLINKBAUD);
|
||||
ppplink.enableIntTx(true);
|
||||
logger.println();
|
||||
logger.printf("\n\nhey, trying to be a PPP server here\n\n");
|
||||
logger.printf("Now try this on your linux host:\n\n");
|
||||
logger.printf("connect a serial<->usb module (e.g. to /dev/ttyUSB1) and link it to the ESP (esprx=%d esptx=%d), then run:\n\n", RX, TX);
|
||||
logger.printf("sudo /usr/sbin/pppd /dev/ttyUSB1 %d noipdefault nocrtscts local defaultroute noauth nodetach debug dump\n\n", PPPLINKBAUD);
|
||||
|
||||
ppp.ifUpCb(PPPConnectedCallback);
|
||||
bool ret = ppp.begin(WiFi.localIP());
|
||||
logger.printf("ppp: %d\n", ret);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.printf("\n\nPPP/NAPT not supported in this configuration\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void loop() {
|
||||
}
|
10
libraries/lwIP_PPP/library.properties
Normal file
10
libraries/lwIP_PPP/library.properties
Normal file
@ -0,0 +1,10 @@
|
||||
name=lwIP_PPP
|
||||
version=1
|
||||
author=lwIP
|
||||
maintainer=esp8266/Arduino
|
||||
sentence=PPP interface
|
||||
paragraph=PPP interface for esp8266 arduino
|
||||
category=Network
|
||||
url=https://github.com/esp8266/Arduino
|
||||
architectures=esp8266
|
||||
dot_a_linkage=true
|
196
libraries/lwIP_PPP/src/PPPServer.cpp
Normal file
196
libraries/lwIP_PPP/src/PPPServer.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
|
||||
// This is still beta / a work in progress
|
||||
|
||||
// testing on linux:
|
||||
// sudo /usr/sbin/pppd /dev/ttyUSB1 38400 noipdefault nocrtscts local defaultroute noauth nodetach debug dump
|
||||
// sudo /usr/sbin/pppd /dev/ttyUSB1 38400 noipdefault nocrtscts local defaultroute noauth
|
||||
|
||||
// proxy arp is needed but we don't have it
|
||||
// http://lwip.100.n7.nabble.com/PPP-proxy-arp-support-tp33286p33345.html
|
||||
// using NAT instead (see in example)
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Schedule.h>
|
||||
#include <IPAddress.h>
|
||||
#include <lwip/dns.h>
|
||||
|
||||
#include "PPPServer.h"
|
||||
|
||||
PPPServer::PPPServer(Stream* sio): _sio(sio), _cb(netif_status_cb_s), _enabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool PPPServer::handlePackets()
|
||||
{
|
||||
size_t avail;
|
||||
if ((avail = _sio->available()) > 0)
|
||||
{
|
||||
// XXX block peeking would be useful here
|
||||
if (avail > _bufsize)
|
||||
{
|
||||
avail = _bufsize;
|
||||
}
|
||||
avail = _sio->readBytes(_buf, avail);
|
||||
pppos_input(_ppp, _buf, avail);
|
||||
}
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
void PPPServer::link_status_cb_s(ppp_pcb* pcb, int err_code, void* ctx)
|
||||
{
|
||||
bool stop = true;
|
||||
netif* nif = ppp_netif(pcb);
|
||||
|
||||
switch (err_code)
|
||||
{
|
||||
case PPPERR_NONE: /* No error. */
|
||||
{
|
||||
#if LWIP_DNS
|
||||
const ip_addr_t *ns;
|
||||
#endif /* LWIP_DNS */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_NONE\n\r");
|
||||
#if LWIP_IPV4
|
||||
ets_printf(" our_ip4addr = %s\n\r", ip4addr_ntoa(netif_ip4_addr(nif)));
|
||||
ets_printf(" his_ipaddr = %s\n\r", ip4addr_ntoa(netif_ip4_gw(nif)));
|
||||
ets_printf(" netmask = %s\n\r", ip4addr_ntoa(netif_ip4_netmask(nif)));
|
||||
#endif /* LWIP_IPV4 */
|
||||
#if LWIP_IPV6
|
||||
ets_printf(" our_ip6addr = %s\n\r", ip6addr_ntoa(netif_ip6_addr(nif, 0)));
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#if LWIP_DNS
|
||||
ns = dns_getserver(0);
|
||||
ets_printf(" dns1 = %s\n\r", ipaddr_ntoa(ns));
|
||||
ns = dns_getserver(1);
|
||||
ets_printf(" dns2 = %s\n\r", ipaddr_ntoa(ns));
|
||||
#endif /* LWIP_DNS */
|
||||
#if PPP_IPV6_SUPPORT
|
||||
ets_printf(" our6_ipaddr = %s\n\r", ip6addr_ntoa(netif_ip6_addr(nif, 0)));
|
||||
#endif /* PPP_IPV6_SUPPORT */
|
||||
}
|
||||
stop = false;
|
||||
break;
|
||||
|
||||
case PPPERR_PARAM: /* Invalid parameter. */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_PARAM\n");
|
||||
break;
|
||||
|
||||
case PPPERR_OPEN: /* Unable to open PPP session. */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_OPEN\n");
|
||||
break;
|
||||
|
||||
case PPPERR_DEVICE: /* Invalid I/O device for PPP. */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_DEVICE\n");
|
||||
break;
|
||||
|
||||
case PPPERR_ALLOC: /* Unable to allocate resources. */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_ALLOC\n");
|
||||
break;
|
||||
|
||||
case PPPERR_USER: /* User interrupt. */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_USER\n");
|
||||
break;
|
||||
|
||||
case PPPERR_CONNECT: /* Connection lost. */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_CONNECT\n");
|
||||
break;
|
||||
|
||||
case PPPERR_AUTHFAIL: /* Failed authentication challenge. */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_AUTHFAIL\n");
|
||||
break;
|
||||
|
||||
case PPPERR_PROTOCOL: /* Failed to meet protocol. */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_PROTOCOL\n");
|
||||
break;
|
||||
|
||||
case PPPERR_PEERDEAD: /* Connection timeout. */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_PEERDEAD\n");
|
||||
break;
|
||||
|
||||
case PPPERR_IDLETIMEOUT: /* Idle Timeout. */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_IDLETIMEOUT\n");
|
||||
break;
|
||||
|
||||
case PPPERR_CONNECTTIME: /* PPPERR_CONNECTTIME. */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_CONNECTTIME\n");
|
||||
break;
|
||||
|
||||
case PPPERR_LOOPBACK: /* Connection timeout. */
|
||||
ets_printf("ppp_link_status_cb: PPPERR_LOOPBACK\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
ets_printf("ppp_link_status_cb: unknown errCode %d\n", err_code);
|
||||
break;
|
||||
}
|
||||
|
||||
if (stop)
|
||||
{
|
||||
netif_remove(&static_cast<PPPServer*>(ctx)->_netif);
|
||||
}
|
||||
}
|
||||
|
||||
u32_t PPPServer::output_cb_s(ppp_pcb* pcb, u8_t* data, u32_t len, void* ctx)
|
||||
{
|
||||
(void)pcb;
|
||||
(void)ctx;
|
||||
return static_cast<PPPServer*>(ctx)->_sio->write(data, len);
|
||||
}
|
||||
|
||||
void PPPServer::netif_status_cb_s(netif* nif)
|
||||
{
|
||||
ets_printf("PPPNETIF: %c%c%d is %s\n", nif->name[0], nif->name[1], nif->num,
|
||||
netif_is_up(nif) ? "UP" : "DOWN");
|
||||
#if LWIP_IPV4
|
||||
ets_printf("IPV4: Host at %s ", ip4addr_ntoa(netif_ip4_addr(nif)));
|
||||
ets_printf("mask %s ", ip4addr_ntoa(netif_ip4_netmask(nif)));
|
||||
ets_printf("gateway %s\n", ip4addr_ntoa(netif_ip4_gw(nif)));
|
||||
#endif /* LWIP_IPV4 */
|
||||
#if LWIP_IPV6
|
||||
ets_printf("IPV6: Host at %s\n", ip6addr_ntoa(netif_ip6_addr(nif, 0)));
|
||||
#endif /* LWIP_IPV6 */
|
||||
ets_printf("FQDN: %s\n", netif_get_hostname(nif));
|
||||
}
|
||||
|
||||
bool PPPServer::begin(const IPAddress& ourAddress, const IPAddress& peer)
|
||||
{
|
||||
// lwip2-src/doc/ppp.txt
|
||||
|
||||
_ppp = pppos_create(&_netif, PPPServer::output_cb_s, PPPServer::link_status_cb_s, this);
|
||||
if (!_ppp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ppp_set_ipcp_ouraddr(_ppp, ip_2_ip4((const ip_addr_t*)ourAddress));
|
||||
ppp_set_ipcp_hisaddr(_ppp, ip_2_ip4((const ip_addr_t*)peer));
|
||||
|
||||
//ip4_addr_t addr;
|
||||
//IP4_ADDR(&addr, 10,0,1,254);
|
||||
//ppp_set_ipcp_dnsaddr(_ppp, 0, &addr);
|
||||
|
||||
//ppp_set_auth(_ppp, PPPAUTHTYPE_ANY, "login", "password");
|
||||
//ppp_set_auth_required(_ppp, 1);
|
||||
|
||||
ppp_set_silent(_ppp, 1);
|
||||
ppp_listen(_ppp);
|
||||
netif_set_status_callback(&_netif, _cb);
|
||||
|
||||
_enabled = true;
|
||||
if (!schedule_recurrent_function_us([&]()
|
||||
{
|
||||
return this->handlePackets();
|
||||
}, 1000))
|
||||
{
|
||||
netif_remove(&_netif);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PPPServer::stop()
|
||||
{
|
||||
_enabled = false;
|
||||
ppp_close(_ppp, 0);
|
||||
}
|
77
libraries/lwIP_PPP/src/PPPServer.h
Normal file
77
libraries/lwIP_PPP/src/PPPServer.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
This file is part of the lwIP TCP/IP stack.
|
||||
|
||||
Author: Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __PPPSERVER_H
|
||||
#define __PPPSERVER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <IPAddress.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <netif/ppp/ppp.h>
|
||||
#include <netif/ppp/pppos.h>
|
||||
|
||||
class PPPServer
|
||||
{
|
||||
public:
|
||||
|
||||
PPPServer(Stream* sio);
|
||||
|
||||
bool begin(const IPAddress& ourAddress, const IPAddress& peer = IPAddress(172, 31, 255, 254));
|
||||
void stop();
|
||||
|
||||
void ifUpCb(void (*cb)(netif*))
|
||||
{
|
||||
_cb = cb;
|
||||
}
|
||||
const ip_addr_t* getPeerAddress() const
|
||||
{
|
||||
return &_netif.gw;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static constexpr size_t _bufsize = 128;
|
||||
Stream* _sio;
|
||||
ppp_pcb* _ppp;
|
||||
netif _netif;
|
||||
void (*_cb)(netif*);
|
||||
uint8_t _buf[_bufsize];
|
||||
bool _enabled;
|
||||
|
||||
// feed ppp from stream - to call on a regular basis or on interrupt
|
||||
bool handlePackets();
|
||||
|
||||
static u32_t output_cb_s(ppp_pcb* pcb, u8_t* data, u32_t len, void* ctx);
|
||||
static void link_status_cb_s(ppp_pcb* pcb, int err_code, void* ctx);
|
||||
static void netif_status_cb_s(netif* nif);
|
||||
|
||||
};
|
||||
|
||||
#endif // __PPPSERVER_H
|
10
libraries/lwIP_enc28j60/library.properties
Normal file
10
libraries/lwIP_enc28j60/library.properties
Normal file
@ -0,0 +1,10 @@
|
||||
name=lwIP_enc28j60
|
||||
version=1
|
||||
author=Nicholas Humfrey
|
||||
maintainer=esp8266/Arduino
|
||||
sentence=Ethernet driver
|
||||
paragraph=ENC28J60 ethernet drivers for lwIP and esp8266 Arduino from https://github.com/njh/EtherSia/tree/master/src/enc28j60.cpp
|
||||
category=Network
|
||||
url=https://github.com/esp8266/Arduino
|
||||
architectures=esp8266
|
||||
dot_a_linkage=true
|
10
libraries/lwIP_enc28j60/src/ENC28J60lwIP.h
Normal file
10
libraries/lwIP_enc28j60/src/ENC28J60lwIP.h
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
#ifndef _ENC28J60LWIP_H
|
||||
#define _ENC28J60LWIP_H
|
||||
|
||||
#include <LwipIntfDev.h>
|
||||
#include <utility/enc28j60.h>
|
||||
|
||||
using ENC28J60lwIP = LwipIntfDev<ENC28J60>;
|
||||
|
||||
#endif // _ENC28J60LWIP_H
|
744
libraries/lwIP_enc28j60/src/utility/enc28j60.cpp
Normal file
744
libraries/lwIP_enc28j60/src/utility/enc28j60.cpp
Normal file
@ -0,0 +1,744 @@
|
||||
/*
|
||||
Copyright (c) 2012-2013, Thingsquare, http://www.thingsquare.com/.
|
||||
Copyright (c) 2016, Nicholas Humfrey
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// original sources: https://github.com/njh/EtherSia/tree/master/src/enc28j60.cpp
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "enc28j60.h"
|
||||
|
||||
|
||||
void serial_printf(const char *fmt, ...)
|
||||
{
|
||||
char buf[128];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, 128, fmt, args);
|
||||
va_end(args);
|
||||
Serial.print(buf);
|
||||
}
|
||||
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define PRINTF(...) do { (void)0; } while (0)
|
||||
#endif
|
||||
|
||||
#define EIE 0x1b
|
||||
#define EIR 0x1c
|
||||
#define ESTAT 0x1d
|
||||
#define ECON2 0x1e
|
||||
#define ECON1 0x1f
|
||||
|
||||
#define ESTAT_CLKRDY 0x01
|
||||
#define ESTAT_TXABRT 0x02
|
||||
|
||||
#define ECON1_RXEN 0x04
|
||||
#define ECON1_TXRTS 0x08
|
||||
|
||||
#define ECON2_AUTOINC 0x80
|
||||
#define ECON2_PKTDEC 0x40
|
||||
|
||||
#define EIR_TXIF 0x08
|
||||
|
||||
#define ERXTX_BANK 0x00
|
||||
|
||||
#define ERDPTL 0x00
|
||||
#define ERDPTH 0x01
|
||||
#define EWRPTL 0x02
|
||||
#define EWRPTH 0x03
|
||||
#define ETXSTL 0x04
|
||||
#define ETXSTH 0x05
|
||||
#define ETXNDL 0x06
|
||||
#define ETXNDH 0x07
|
||||
#define ERXSTL 0x08
|
||||
#define ERXSTH 0x09
|
||||
#define ERXNDL 0x0a
|
||||
#define ERXNDH 0x0b
|
||||
#define ERXRDPTL 0x0c
|
||||
#define ERXRDPTH 0x0d
|
||||
|
||||
#define RX_BUF_START 0x0000
|
||||
#define RX_BUF_END 0x0fff
|
||||
|
||||
#define TX_BUF_START 0x1200
|
||||
|
||||
/* MACONx registers are in bank 2 */
|
||||
#define MACONX_BANK 0x02
|
||||
|
||||
#define MACON1 0x00
|
||||
#define MACON3 0x02
|
||||
#define MACON4 0x03
|
||||
#define MABBIPG 0x04
|
||||
#define MAIPGL 0x06
|
||||
#define MAIPGH 0x07
|
||||
#define MAMXFLL 0x0a
|
||||
#define MAMXFLH 0x0b
|
||||
|
||||
#define MACON1_TXPAUS 0x08
|
||||
#define MACON1_RXPAUS 0x04
|
||||
#define MACON1_MARXEN 0x01
|
||||
|
||||
#define MACON3_PADCFG_FULL 0xe0
|
||||
#define MACON3_TXCRCEN 0x10
|
||||
#define MACON3_FRMLNEN 0x02
|
||||
#define MACON3_FULDPX 0x01
|
||||
|
||||
#define MAX_MAC_LENGTH 1518
|
||||
|
||||
#define MAADRX_BANK 0x03
|
||||
#define MAADR1 0x04 /* MAADR<47:40> */
|
||||
#define MAADR2 0x05 /* MAADR<39:32> */
|
||||
#define MAADR3 0x02 /* MAADR<31:24> */
|
||||
#define MAADR4 0x03 /* MAADR<23:16> */
|
||||
#define MAADR5 0x00 /* MAADR<15:8> */
|
||||
#define MAADR6 0x01 /* MAADR<7:0> */
|
||||
#define MISTAT 0x0a
|
||||
#define EREVID 0x12
|
||||
|
||||
#define EPKTCNT_BANK 0x01
|
||||
#define ERXFCON 0x18
|
||||
#define EPKTCNT 0x19
|
||||
|
||||
#define ERXFCON_UCEN 0x80
|
||||
#define ERXFCON_ANDOR 0x40
|
||||
#define ERXFCON_CRCEN 0x20
|
||||
#define ERXFCON_MCEN 0x02
|
||||
#define ERXFCON_BCEN 0x01
|
||||
|
||||
// The ENC28J60 SPI Interface supports clock speeds up to 20 MHz
|
||||
static const SPISettings spiSettings(20000000, MSBFIRST, SPI_MODE0);
|
||||
|
||||
ENC28J60::ENC28J60(int8_t cs, SPIClass& spi, int8_t intr):
|
||||
_bank(ERXTX_BANK), _cs(cs), _spi(spi)
|
||||
{
|
||||
(void)intr;
|
||||
}
|
||||
|
||||
void
|
||||
ENC28J60::enc28j60_arch_spi_select(void)
|
||||
{
|
||||
SPI.beginTransaction(spiSettings);
|
||||
digitalWrite(_cs, LOW);
|
||||
}
|
||||
|
||||
void
|
||||
ENC28J60::enc28j60_arch_spi_deselect(void)
|
||||
{
|
||||
digitalWrite(_cs, HIGH);
|
||||
SPI.endTransaction();
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
ENC28J60::is_mac_mii_reg(uint8_t reg)
|
||||
{
|
||||
/* MAC or MII register (otherwise, ETH register)? */
|
||||
switch (_bank)
|
||||
{
|
||||
case MACONX_BANK:
|
||||
return reg < EIE;
|
||||
case MAADRX_BANK:
|
||||
return reg <= MAADR2 || reg == MISTAT;
|
||||
case ERXTX_BANK:
|
||||
case EPKTCNT_BANK:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
ENC28J60::readreg(uint8_t reg)
|
||||
{
|
||||
uint8_t r;
|
||||
enc28j60_arch_spi_select();
|
||||
SPI.transfer(0x00 | (reg & 0x1f));
|
||||
if (is_mac_mii_reg(reg))
|
||||
{
|
||||
/* MAC and MII registers require that a dummy byte be read first. */
|
||||
SPI.transfer(0);
|
||||
}
|
||||
r = SPI.transfer(0);
|
||||
enc28j60_arch_spi_deselect();
|
||||
return r;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ENC28J60::writereg(uint8_t reg, uint8_t data)
|
||||
{
|
||||
enc28j60_arch_spi_select();
|
||||
SPI.transfer(0x40 | (reg & 0x1f));
|
||||
SPI.transfer(data);
|
||||
enc28j60_arch_spi_deselect();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ENC28J60::setregbitfield(uint8_t reg, uint8_t mask)
|
||||
{
|
||||
if (is_mac_mii_reg(reg))
|
||||
{
|
||||
writereg(reg, readreg(reg) | mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
enc28j60_arch_spi_select();
|
||||
SPI.transfer(0x80 | (reg & 0x1f));
|
||||
SPI.transfer(mask);
|
||||
enc28j60_arch_spi_deselect();
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ENC28J60::clearregbitfield(uint8_t reg, uint8_t mask)
|
||||
{
|
||||
if (is_mac_mii_reg(reg))
|
||||
{
|
||||
writereg(reg, readreg(reg) & ~mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
enc28j60_arch_spi_select();
|
||||
SPI.transfer(0xa0 | (reg & 0x1f));
|
||||
SPI.transfer(mask);
|
||||
enc28j60_arch_spi_deselect();
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ENC28J60::setregbank(uint8_t new_bank)
|
||||
{
|
||||
writereg(ECON1, (readreg(ECON1) & 0xfc) | (new_bank & 0x03));
|
||||
_bank = new_bank;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ENC28J60::writedata(const uint8_t *data, int datalen)
|
||||
{
|
||||
int i;
|
||||
enc28j60_arch_spi_select();
|
||||
/* The Write Buffer Memory (WBM) command is 0 1 1 1 1 0 1 0 */
|
||||
SPI.transfer(0x7a);
|
||||
for (i = 0; i < datalen; i++)
|
||||
{
|
||||
SPI.transfer(data[i]);
|
||||
}
|
||||
enc28j60_arch_spi_deselect();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ENC28J60::writedatabyte(uint8_t byte)
|
||||
{
|
||||
writedata(&byte, 1);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
ENC28J60::readdata(uint8_t *buf, int len)
|
||||
{
|
||||
int i;
|
||||
enc28j60_arch_spi_select();
|
||||
/* THe Read Buffer Memory (RBM) command is 0 0 1 1 1 0 1 0 */
|
||||
SPI.transfer(0x3a);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
buf[i] = SPI.transfer(0);
|
||||
}
|
||||
enc28j60_arch_spi_deselect();
|
||||
return i;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
ENC28J60::readdatabyte(void)
|
||||
{
|
||||
uint8_t r;
|
||||
readdata(&r, 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ENC28J60::softreset(void)
|
||||
{
|
||||
enc28j60_arch_spi_select();
|
||||
/* The System Command (soft reset) is 1 1 1 1 1 1 1 1 */
|
||||
SPI.transfer(0xff);
|
||||
enc28j60_arch_spi_deselect();
|
||||
_bank = ERXTX_BANK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
//#if DEBUG
|
||||
uint8_t
|
||||
ENC28J60::readrev(void)
|
||||
{
|
||||
uint8_t rev;
|
||||
setregbank(MAADRX_BANK);
|
||||
rev = readreg(EREVID);
|
||||
switch (rev)
|
||||
{
|
||||
case 2:
|
||||
return 1;
|
||||
case 6:
|
||||
return 7;
|
||||
default:
|
||||
return rev;
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
bool
|
||||
ENC28J60::reset(void)
|
||||
{
|
||||
PRINTF("enc28j60: resetting chip\n");
|
||||
|
||||
pinMode(_cs, OUTPUT);
|
||||
digitalWrite(_cs, HIGH);
|
||||
SPI.begin();
|
||||
|
||||
/*
|
||||
6.0 INITIALIZATION
|
||||
|
||||
Before the ENC28J60 can be used to transmit and receive packets,
|
||||
certain device settings must be initialized. Depending on the
|
||||
application, some configuration options may need to be
|
||||
changed. Normally, these tasks may be accomplished once after
|
||||
Reset and do not need to be changed thereafter.
|
||||
|
||||
6.1 Receive Buffer
|
||||
|
||||
Before receiving any packets, the receive buffer must be
|
||||
initialized by programming the ERXST and ERXND pointers. All
|
||||
memory between and including the ERXST and ERXND addresses will be
|
||||
dedicated to the receive hardware. It is recommended that the
|
||||
ERXST pointer be programmed with an even address.
|
||||
|
||||
Applications expecting large amounts of data and frequent packet
|
||||
delivery may wish to allocate most of the memory as the receive
|
||||
buffer. Applications that may need to save older packets or have
|
||||
several packets ready for transmission should allocate less
|
||||
memory.
|
||||
|
||||
When programming the ERXST pointer, the ERXWRPT registers will
|
||||
automatically be updated with the same values. The address in
|
||||
ERXWRPT will be used as the starting location when the receive
|
||||
hardware begins writing received data. For tracking purposes, the
|
||||
ERXRDPT registers should additionally be programmed with the same
|
||||
value. To program ERXRDPT, the host controller must write to
|
||||
ERXRDPTL first, followed by ERXRDPTH. See Section 7.2.4 “Freeing
|
||||
Receive Buffer Space for more information
|
||||
|
||||
6.2 Transmission Buffer
|
||||
|
||||
All memory which is not used by the receive buffer is considered
|
||||
the transmission buffer. Data which is to be transmitted should be
|
||||
written into any unused space. After a packet is transmitted,
|
||||
however, the hardware will write a seven-byte status vector into
|
||||
memory after the last byte in the packet. Therefore, the host
|
||||
controller should leave at least seven bytes between each packet
|
||||
and the beginning of the receive buffer. No explicit action is
|
||||
required to initialize the transmission buffer.
|
||||
|
||||
6.3 Receive Filters
|
||||
|
||||
The appropriate receive filters should be enabled or disabled by
|
||||
writing to the ERXFCON register. See Section 8.0 “Receive Filters
|
||||
for information on how to configure it.
|
||||
|
||||
6.4 Waiting For OST
|
||||
|
||||
If the initialization procedure is being executed immediately
|
||||
following a Power-on Reset, the ESTAT.CLKRDY bit should be polled
|
||||
to make certain that enough time has elapsed before proceeding to
|
||||
modify the MAC and PHY registers. For more information on the OST,
|
||||
see Section 2.2 “Oscillator Start-up Timer.
|
||||
*/
|
||||
|
||||
softreset();
|
||||
|
||||
/* Workaround for erratum #2. */
|
||||
delayMicroseconds(1000);
|
||||
|
||||
/* Wait for OST */
|
||||
PRINTF("waiting for ESTAT_CLKRDY\n");
|
||||
while ((readreg(ESTAT) & ESTAT_CLKRDY) == 0) {};
|
||||
PRINTF("ESTAT_CLKRDY\n");
|
||||
|
||||
setregbank(ERXTX_BANK);
|
||||
/* Set up receive buffer */
|
||||
writereg(ERXSTL, RX_BUF_START & 0xff);
|
||||
writereg(ERXSTH, RX_BUF_START >> 8);
|
||||
writereg(ERXNDL, RX_BUF_END & 0xff);
|
||||
writereg(ERXNDH, RX_BUF_END >> 8);
|
||||
writereg(ERDPTL, RX_BUF_START & 0xff);
|
||||
writereg(ERDPTH, RX_BUF_START >> 8);
|
||||
writereg(ERXRDPTL, RX_BUF_END & 0xff);
|
||||
writereg(ERXRDPTH, RX_BUF_END >> 8);
|
||||
|
||||
/* Receive filters */
|
||||
setregbank(EPKTCNT_BANK);
|
||||
writereg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_MCEN);
|
||||
|
||||
/*
|
||||
6.5 MAC Initialization Settings
|
||||
|
||||
Several of the MAC registers require configuration during
|
||||
initialization. This only needs to be done once; the order of
|
||||
programming is unimportant.
|
||||
|
||||
1. Set the MARXEN bit in MACON1 to enable the MAC to receive
|
||||
frames. If using full duplex, most applications should also set
|
||||
TXPAUS and RXPAUS to allow IEEE defined flow control to function.
|
||||
|
||||
2. Configure the PADCFG, TXCRCEN and FULDPX bits of MACON3. Most
|
||||
applications should enable automatic padding to at least 60 bytes
|
||||
and always append a valid CRC. For convenience, many applications
|
||||
may wish to set the FRMLNEN bit as well to enable frame length
|
||||
status reporting. The FULDPX bit should be set if the application
|
||||
will be connected to a full-duplex configured remote node;
|
||||
otherwise, it should be left clear.
|
||||
|
||||
3. Configure the bits in MACON4. For conformance to the IEEE 802.3
|
||||
standard, set the DEFER bit.
|
||||
|
||||
4. Program the MAMXFL registers with the maximum frame length to
|
||||
be permitted to be received or transmitted. Normal network nodes
|
||||
are designed to handle packets that are 1518 bytes or less.
|
||||
|
||||
5. Configure the Back-to-Back Inter-Packet Gap register,
|
||||
MABBIPG. Most applications will program this register with 15h
|
||||
when Full-Duplex mode is used and 12h when Half-Duplex mode is
|
||||
used.
|
||||
|
||||
6. Configure the Non-Back-to-Back Inter-Packet Gap register low
|
||||
byte, MAIPGL. Most applications will program this register with
|
||||
12h.
|
||||
|
||||
7. If half duplex is used, the Non-Back-to-Back Inter-Packet Gap
|
||||
register high byte, MAIPGH, should be programmed. Most
|
||||
applications will program this register to 0Ch.
|
||||
|
||||
8. If Half-Duplex mode is used, program the Retransmission and
|
||||
Collision Window registers, MACLCON1 and MACLCON2. Most
|
||||
applications will not need to change the default Reset values. If
|
||||
the network is spread over exceptionally long cables, the default
|
||||
value of MACLCON2 may need to be increased.
|
||||
|
||||
9. Program the local MAC address into the MAADR1:MAADR6 registers.
|
||||
*/
|
||||
|
||||
setregbank(MACONX_BANK);
|
||||
|
||||
/* Turn on reception and IEEE-defined flow control */
|
||||
setregbitfield(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
|
||||
|
||||
/* Set padding, crc, full duplex */
|
||||
setregbitfield(MACON3, MACON3_PADCFG_FULL | MACON3_TXCRCEN | MACON3_FULDPX |
|
||||
MACON3_FRMLNEN);
|
||||
|
||||
/* Don't modify MACON4 */
|
||||
|
||||
/* Set maximum frame length in MAMXFL */
|
||||
writereg(MAMXFLL, MAX_MAC_LENGTH & 0xff);
|
||||
writereg(MAMXFLH, MAX_MAC_LENGTH >> 8);
|
||||
|
||||
/* Set back-to-back inter packet gap */
|
||||
writereg(MABBIPG, 0x15);
|
||||
|
||||
/* Set non-back-to-back packet gap */
|
||||
writereg(MAIPGL, 0x12);
|
||||
|
||||
/* Set MAC address */
|
||||
setregbank(MAADRX_BANK);
|
||||
writereg(MAADR6, _localMac[5]);
|
||||
writereg(MAADR5, _localMac[4]);
|
||||
writereg(MAADR4, _localMac[3]);
|
||||
writereg(MAADR3, _localMac[2]);
|
||||
writereg(MAADR2, _localMac[1]);
|
||||
writereg(MAADR1, _localMac[0]);
|
||||
|
||||
/*
|
||||
6.6 PHY Initialization Settings
|
||||
|
||||
Depending on the application, bits in three of the PHY module’s
|
||||
registers may also require configuration. The PHCON1.PDPXMD bit
|
||||
partially controls the device’s half/full-duplex
|
||||
configuration. Normally, this bit is initialized correctly by the
|
||||
external circuitry (see Section 2.6 “LED Configuration). If the
|
||||
external circuitry is not present or incorrect, however, the host
|
||||
controller must program the bit properly. Alternatively, for an
|
||||
externally configurable system, the PDPXMD bit may be read and the
|
||||
FULDPX bit be programmed to match.
|
||||
|
||||
For proper duplex operation, the PHCON1.PDPXMD bit must also match
|
||||
the value of the MACON3.FULDPX bit.
|
||||
|
||||
If using half duplex, the host controller may wish to set the
|
||||
PHCON2.HDLDIS bit to prevent automatic loopback of the data which
|
||||
is transmitted. The PHY register, PHLCON, controls the outputs of
|
||||
LEDA and LEDB. If an application requires a LED configuration
|
||||
other than the default, PHLCON must be altered to match the new
|
||||
requirements. The settings for LED operation are discussed in
|
||||
Section 2.6 “LED Configuration. The PHLCON register is shown in
|
||||
Register 2-2 (page 9).
|
||||
*/
|
||||
|
||||
/* Don't worry about PHY configuration for now */
|
||||
|
||||
/* Turn on autoincrement for buffer access */
|
||||
setregbitfield(ECON2, ECON2_AUTOINC);
|
||||
|
||||
/* Turn on reception */
|
||||
writereg(ECON1, ECON1_RXEN);
|
||||
|
||||
return true;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
boolean
|
||||
ENC28J60::begin(const uint8_t *address)
|
||||
{
|
||||
_localMac = address;
|
||||
|
||||
bool ret = reset();
|
||||
uint8_t rev = readrev();
|
||||
|
||||
PRINTF("ENC28J60 rev. B%d\n", rev);
|
||||
|
||||
return ret && rev != 255;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
uint16_t
|
||||
ENC28J60::sendFrame(const uint8_t *data, uint16_t datalen)
|
||||
{
|
||||
uint16_t dataend;
|
||||
|
||||
/*
|
||||
1. Appropriately program the ETXST pointer to point to an unused
|
||||
location in memory. It will point to the per packet control
|
||||
byte. In the example, it would be programmed to 0120h. It is
|
||||
recommended that an even address be used for ETXST.
|
||||
|
||||
2. Use the WBM SPI command to write the per packet control byte,
|
||||
the destination address, the source MAC address, the
|
||||
type/length and the data payload.
|
||||
|
||||
3. Appropriately program the ETXND pointer. It should point to the
|
||||
last byte in the data payload. In the example, it would be
|
||||
programmed to 0156h.
|
||||
|
||||
4. Clear EIR.TXIF, set EIE.TXIE and set EIE.INTIE to enable an
|
||||
interrupt when done (if desired).
|
||||
|
||||
5. Start the transmission process by setting
|
||||
ECON1.TXRTS.
|
||||
*/
|
||||
|
||||
setregbank(ERXTX_BANK);
|
||||
/* Set up the transmit buffer pointer */
|
||||
writereg(ETXSTL, TX_BUF_START & 0xff);
|
||||
writereg(ETXSTH, TX_BUF_START >> 8);
|
||||
writereg(EWRPTL, TX_BUF_START & 0xff);
|
||||
writereg(EWRPTH, TX_BUF_START >> 8);
|
||||
|
||||
/* Write the transmission control register as the first byte of the
|
||||
output packet. We write 0x00 to indicate that the default
|
||||
configuration (the values in MACON3) will be used. */
|
||||
writedatabyte(0x00); /* MACON3 */
|
||||
|
||||
writedata(data, datalen);
|
||||
|
||||
/* Write a pointer to the last data byte. */
|
||||
dataend = TX_BUF_START + datalen;
|
||||
writereg(ETXNDL, dataend & 0xff);
|
||||
writereg(ETXNDH, dataend >> 8);
|
||||
|
||||
/* Clear EIR.TXIF */
|
||||
clearregbitfield(EIR, EIR_TXIF);
|
||||
|
||||
/* Don't care about interrupts for now */
|
||||
|
||||
/* Send the packet */
|
||||
setregbitfield(ECON1, ECON1_TXRTS);
|
||||
while ((readreg(ECON1) & ECON1_TXRTS) > 0);
|
||||
|
||||
#if DEBUG
|
||||
if ((readreg(ESTAT) & ESTAT_TXABRT) != 0)
|
||||
{
|
||||
uint16_t erdpt;
|
||||
uint8_t tsv[7];
|
||||
erdpt = (readreg(ERDPTH) << 8) | readreg(ERDPTL);
|
||||
writereg(ERDPTL, (dataend + 1) & 0xff);
|
||||
writereg(ERDPTH, (dataend + 1) >> 8);
|
||||
readdata(tsv, sizeof(tsv));
|
||||
writereg(ERDPTL, erdpt & 0xff);
|
||||
writereg(ERDPTH, erdpt >> 8);
|
||||
PRINTF("enc28j60: tx err: %d: %02x:%02x:%02x:%02x:%02x:%02x\n"
|
||||
" tsv: %02x%02x%02x%02x%02x%02x%02x\n", datalen,
|
||||
0xff & data[0], 0xff & data[1], 0xff & data[2],
|
||||
0xff & data[3], 0xff & data[4], 0xff & data[5],
|
||||
tsv[6], tsv[5], tsv[4], tsv[3], tsv[2], tsv[1], tsv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINTF("enc28j60: tx: %d: %02x:%02x:%02x:%02x:%02x:%02x\n", datalen,
|
||||
0xff & data[0], 0xff & data[1], 0xff & data[2],
|
||||
0xff & data[3], 0xff & data[4], 0xff & data[5]);
|
||||
}
|
||||
#endif
|
||||
|
||||
//sent_packets++;
|
||||
//PRINTF("enc28j60: sent_packets %d\n", sent_packets);
|
||||
return datalen;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
uint16_t
|
||||
ENC28J60::readFrame(uint8_t *buffer, uint16_t bufsize)
|
||||
{
|
||||
readFrameSize();
|
||||
return readFrameData(buffer, bufsize);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ENC28J60::readFrameSize()
|
||||
{
|
||||
uint8_t n;
|
||||
|
||||
uint8_t nxtpkt[2];
|
||||
uint8_t status[2];
|
||||
uint8_t length[2];
|
||||
|
||||
setregbank(EPKTCNT_BANK);
|
||||
n = readreg(EPKTCNT);
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRINTF("enc28j60: EPKTCNT 0x%02x\n", n);
|
||||
|
||||
setregbank(ERXTX_BANK);
|
||||
/* Read the next packet pointer */
|
||||
nxtpkt[0] = readdatabyte();
|
||||
nxtpkt[1] = readdatabyte();
|
||||
_next = (nxtpkt[1] << 8) + nxtpkt[0];
|
||||
|
||||
PRINTF("enc28j60: nxtpkt 0x%02x%02x\n", _nxtpkt[1], _nxtpkt[0]);
|
||||
|
||||
length[0] = readdatabyte();
|
||||
length[1] = readdatabyte();
|
||||
_len = (length[1] << 8) + length[0];
|
||||
|
||||
PRINTF("enc28j60: length 0x%02x%02x\n", length[1], length[0]);
|
||||
|
||||
status[0] = readdatabyte();
|
||||
status[1] = readdatabyte();
|
||||
|
||||
/* This statement is just to avoid a compiler warning: */
|
||||
(void)status[0];
|
||||
PRINTF("enc28j60: status 0x%02x%02x\n", status[1], status[0]);
|
||||
|
||||
return _len;
|
||||
}
|
||||
|
||||
void
|
||||
ENC28J60::discardFrame(uint16_t framesize)
|
||||
{
|
||||
(void)framesize;
|
||||
(void)readFrameData(nullptr, 0);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ENC28J60::readFrameData(uint8_t *buffer, uint16_t framesize)
|
||||
{
|
||||
if (framesize < _len)
|
||||
{
|
||||
|
||||
buffer = nullptr;
|
||||
|
||||
/* flush rx fifo */
|
||||
for (uint16_t i = 0; i < _len; i++)
|
||||
{
|
||||
readdatabyte();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
readdata(buffer, _len);
|
||||
}
|
||||
|
||||
/* Read an additional byte at odd lengths, to avoid FIFO corruption */
|
||||
if ((_len % 2) != 0)
|
||||
{
|
||||
readdatabyte();
|
||||
}
|
||||
|
||||
/* Errata #14 */
|
||||
if (_next == RX_BUF_START)
|
||||
{
|
||||
_next = RX_BUF_END;
|
||||
}
|
||||
else
|
||||
{
|
||||
_next = _next - 1;
|
||||
}
|
||||
writereg(ERXRDPTL, _next & 0xff);
|
||||
writereg(ERXRDPTH, _next >> 8);
|
||||
|
||||
setregbitfield(ECON2, ECON2_PKTDEC);
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
PRINTF("enc28j60: rx err: flushed %d\n", _len);
|
||||
return 0;
|
||||
}
|
||||
PRINTF("enc28j60: rx: %d: %02x:%02x:%02x:%02x:%02x:%02x\n", _len,
|
||||
0xff & buffer[0], 0xff & buffer[1], 0xff & buffer[2],
|
||||
0xff & buffer[3], 0xff & buffer[4], 0xff & buffer[5]);
|
||||
|
||||
//received_packets++;
|
||||
//PRINTF("enc28j60: received_packets %d\n", received_packets);
|
||||
|
||||
return _len;
|
||||
}
|
149
libraries/lwIP_enc28j60/src/utility/enc28j60.h
Normal file
149
libraries/lwIP_enc28j60/src/utility/enc28j60.h
Normal file
@ -0,0 +1,149 @@
|
||||
/**
|
||||
Header file for direct Ethernet frame access to the ENC28J60 controller
|
||||
@file enc28j60.h
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2012-2013, Thingsquare, http://www.thingsquare.com/.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// original sources: https://github.com/njh/EtherSia/tree/master/src/enc28j60.h
|
||||
|
||||
#ifndef ENC28J60_H
|
||||
#define ENC28J60_H
|
||||
|
||||
#include <SPI.h>
|
||||
|
||||
/**
|
||||
Send and receive Ethernet frames directly using a ENC28J60 controller.
|
||||
*/
|
||||
class ENC28J60
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
Constructor that uses the default hardware SPI pins
|
||||
@param cs the Arduino Chip Select / Slave Select pin (default 10 on Uno)
|
||||
*/
|
||||
ENC28J60(int8_t cs = SS, SPIClass& spi = SPI, int8_t intr = -1);
|
||||
|
||||
/**
|
||||
Initialise the Ethernet controller
|
||||
Must be called before sending or receiving Ethernet frames
|
||||
|
||||
@param address the local MAC address for the Ethernet interface
|
||||
@return Returns true if setting up the Ethernet interface was successful
|
||||
*/
|
||||
boolean begin(const uint8_t *address);
|
||||
|
||||
/**
|
||||
Send an Ethernet frame
|
||||
@param data a pointer to the data to send
|
||||
@param datalen the length of the data in the packet
|
||||
@return the number of bytes transmitted
|
||||
*/
|
||||
virtual uint16_t sendFrame(const uint8_t *data, uint16_t datalen);
|
||||
|
||||
/**
|
||||
Read an Ethernet frame
|
||||
@param buffer a pointer to a buffer to write the packet to
|
||||
@param bufsize the available space in the buffer
|
||||
@return the length of the received packet
|
||||
or 0 if no packet was received
|
||||
*/
|
||||
virtual uint16_t readFrame(uint8_t *buffer, uint16_t bufsize);
|
||||
|
||||
protected:
|
||||
|
||||
static constexpr bool interruptIsPossible()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
Read an Ethernet frame size
|
||||
@return the length of data do receive
|
||||
or 0 if no frame was received
|
||||
*/
|
||||
uint16_t readFrameSize();
|
||||
|
||||
/**
|
||||
discard an Ethernet frame
|
||||
@param framesize readFrameSize()'s result
|
||||
*/
|
||||
void discardFrame(uint16_t framesize);
|
||||
|
||||
/**
|
||||
Read an Ethernet frame data
|
||||
readFrameSize() must be called first,
|
||||
its result must be passed into framesize parameter
|
||||
@param buffer a pointer to a buffer to write the frame to
|
||||
@param framesize readFrameSize()'s result
|
||||
@return the length of the received frame
|
||||
or 0 if a problem occured
|
||||
*/
|
||||
uint16_t readFrameData(uint8_t *frame, uint16_t framesize);
|
||||
|
||||
private:
|
||||
|
||||
uint8_t is_mac_mii_reg(uint8_t reg);
|
||||
uint8_t readreg(uint8_t reg);
|
||||
void writereg(uint8_t reg, uint8_t data);
|
||||
void setregbitfield(uint8_t reg, uint8_t mask);
|
||||
void clearregbitfield(uint8_t reg, uint8_t mask);
|
||||
void setregbank(uint8_t new_bank);
|
||||
void writedata(const uint8_t *data, int datalen);
|
||||
void writedatabyte(uint8_t byte);
|
||||
int readdata(uint8_t *buf, int len);
|
||||
uint8_t readdatabyte(void);
|
||||
void softreset(void);
|
||||
uint8_t readrev(void);
|
||||
bool reset(void);
|
||||
|
||||
void enc28j60_arch_spi_init(void);
|
||||
uint8_t enc28j60_arch_spi_write(uint8_t data);
|
||||
uint8_t enc28j60_arch_spi_read(void);
|
||||
void enc28j60_arch_spi_select(void);
|
||||
void enc28j60_arch_spi_deselect(void);
|
||||
|
||||
// Previously defined in contiki/core/sys/clock.h
|
||||
void clock_delay_usec(uint16_t dt);
|
||||
|
||||
uint8_t _bank;
|
||||
int8_t _cs;
|
||||
SPIClass& _spi;
|
||||
|
||||
const uint8_t *_localMac;
|
||||
|
||||
/* readFrame*() state */
|
||||
uint16_t _next, _len;
|
||||
};
|
||||
|
||||
#endif /* ENC28J60_H */
|
10
libraries/lwIP_w5100/library.properties
Normal file
10
libraries/lwIP_w5100/library.properties
Normal file
@ -0,0 +1,10 @@
|
||||
name=lwIP_w5500
|
||||
version=1
|
||||
author=Nicholas Humfrey
|
||||
maintainer=esp8266/Arduino
|
||||
sentence=Ethernet driver
|
||||
paragraph=Wiznet5100 ethernet drivers for lwIP and esp8266 Arduino from https://github.com/njh/W5100MacRaw
|
||||
category=Network
|
||||
url=https://github.com/esp8266/Arduino
|
||||
architectures=esp8266
|
||||
dot_a_linkage=true
|
10
libraries/lwIP_w5100/src/W5100lwIP.h
Normal file
10
libraries/lwIP_w5100/src/W5100lwIP.h
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
#ifndef _W5100LWIP_H
|
||||
#define _W5100LWIP_H
|
||||
|
||||
#include <LwipIntfDev.h>
|
||||
#include <utility/w5100.h>
|
||||
|
||||
using Wiznet5100lwIP = LwipIntfDev<Wiznet5100>;
|
||||
|
||||
#endif // _W5500LWIP_H
|
369
libraries/lwIP_w5100/src/utility/w5100.cpp
Normal file
369
libraries/lwIP_w5100/src/utility/w5100.cpp
Normal file
@ -0,0 +1,369 @@
|
||||
/*
|
||||
Copyright (c) 2013, WIZnet Co., Ltd.
|
||||
Copyright (c) 2016, Nicholas Humfrey
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// original sources: https://github.com/njh/W5100MacRaw
|
||||
|
||||
#include <SPI.h>
|
||||
#include "w5100.h"
|
||||
|
||||
|
||||
uint8_t Wiznet5100::wizchip_read(uint16_t address)
|
||||
{
|
||||
uint8_t ret;
|
||||
|
||||
wizchip_cs_select();
|
||||
_spi.transfer(0x0F);
|
||||
_spi.transfer((address & 0xFF00) >> 8);
|
||||
_spi.transfer((address & 0x00FF) >> 0);
|
||||
ret = _spi.transfer(0);
|
||||
wizchip_cs_deselect();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t Wiznet5100::wizchip_read_word(uint16_t address)
|
||||
{
|
||||
return ((uint16_t)wizchip_read(address) << 8) + wizchip_read(address + 1);
|
||||
}
|
||||
|
||||
|
||||
void Wiznet5100::wizchip_read_buf(uint16_t address, uint8_t* pBuf, uint16_t len)
|
||||
{
|
||||
for (uint16_t i = 0; i < len; i++)
|
||||
{
|
||||
pBuf[i] = wizchip_read(address + i);
|
||||
}
|
||||
}
|
||||
|
||||
void Wiznet5100::wizchip_write(uint16_t address, uint8_t wb)
|
||||
{
|
||||
wizchip_cs_select();
|
||||
_spi.transfer(0xF0);
|
||||
_spi.transfer((address & 0xFF00) >> 8);
|
||||
_spi.transfer((address & 0x00FF) >> 0);
|
||||
_spi.transfer(wb); // Data write (write 1byte data)
|
||||
wizchip_cs_deselect();
|
||||
}
|
||||
|
||||
void Wiznet5100::wizchip_write_word(uint16_t address, uint16_t word)
|
||||
{
|
||||
wizchip_write(address, (uint8_t)(word >> 8));
|
||||
wizchip_write(address + 1, (uint8_t) word);
|
||||
}
|
||||
|
||||
void Wiznet5100::wizchip_write_buf(uint16_t address, const uint8_t* pBuf, uint16_t len)
|
||||
{
|
||||
for (uint16_t i = 0; i < len; i++)
|
||||
{
|
||||
wizchip_write(address + i, pBuf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Wiznet5100::setSn_CR(uint8_t cr)
|
||||
{
|
||||
// Write the command to the Command Register
|
||||
wizchip_write(Sn_CR, cr);
|
||||
|
||||
// Now wait for the command to complete
|
||||
while (wizchip_read(Sn_CR));
|
||||
}
|
||||
|
||||
uint16_t Wiznet5100::getSn_TX_FSR()
|
||||
{
|
||||
uint16_t val = 0, val1 = 0;
|
||||
do
|
||||
{
|
||||
val1 = wizchip_read_word(Sn_TX_FSR);
|
||||
if (val1 != 0)
|
||||
{
|
||||
val = wizchip_read_word(Sn_TX_FSR);
|
||||
}
|
||||
} while (val != val1);
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
uint16_t Wiznet5100::getSn_RX_RSR()
|
||||
{
|
||||
uint16_t val = 0, val1 = 0;
|
||||
do
|
||||
{
|
||||
val1 = wizchip_read_word(Sn_RX_RSR);
|
||||
if (val1 != 0)
|
||||
{
|
||||
val = wizchip_read_word(Sn_RX_RSR);
|
||||
}
|
||||
} while (val != val1);
|
||||
return val;
|
||||
}
|
||||
|
||||
void Wiznet5100::wizchip_send_data(const uint8_t *wizdata, uint16_t len)
|
||||
{
|
||||
uint16_t ptr;
|
||||
uint16_t size;
|
||||
uint16_t dst_mask;
|
||||
uint16_t dst_ptr;
|
||||
|
||||
ptr = getSn_TX_WR();
|
||||
|
||||
dst_mask = ptr & TxBufferMask;
|
||||
dst_ptr = TxBufferAddress + dst_mask;
|
||||
|
||||
if (dst_mask + len > TxBufferLength)
|
||||
{
|
||||
size = TxBufferLength - dst_mask;
|
||||
wizchip_write_buf(dst_ptr, wizdata, size);
|
||||
wizdata += size;
|
||||
size = len - size;
|
||||
dst_ptr = TxBufferAddress;
|
||||
wizchip_write_buf(dst_ptr, wizdata, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
wizchip_write_buf(dst_ptr, wizdata, len);
|
||||
}
|
||||
|
||||
ptr += len;
|
||||
|
||||
setSn_TX_WR(ptr);
|
||||
}
|
||||
|
||||
void Wiznet5100::wizchip_recv_data(uint8_t *wizdata, uint16_t len)
|
||||
{
|
||||
uint16_t ptr;
|
||||
uint16_t size;
|
||||
uint16_t src_mask;
|
||||
uint16_t src_ptr;
|
||||
|
||||
ptr = getSn_RX_RD();
|
||||
|
||||
src_mask = ptr & RxBufferMask;
|
||||
src_ptr = RxBufferAddress + src_mask;
|
||||
|
||||
|
||||
if ((src_mask + len) > RxBufferLength)
|
||||
{
|
||||
size = RxBufferLength - src_mask;
|
||||
wizchip_read_buf(src_ptr, wizdata, size);
|
||||
wizdata += size;
|
||||
size = len - size;
|
||||
src_ptr = RxBufferAddress;
|
||||
wizchip_read_buf(src_ptr, wizdata, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
wizchip_read_buf(src_ptr, wizdata, len);
|
||||
}
|
||||
|
||||
ptr += len;
|
||||
|
||||
setSn_RX_RD(ptr);
|
||||
}
|
||||
|
||||
void Wiznet5100::wizchip_recv_ignore(uint16_t len)
|
||||
{
|
||||
uint16_t ptr;
|
||||
|
||||
ptr = getSn_RX_RD();
|
||||
ptr += len;
|
||||
setSn_RX_RD(ptr);
|
||||
}
|
||||
|
||||
void Wiznet5100::wizchip_sw_reset()
|
||||
{
|
||||
setMR(MR_RST);
|
||||
getMR(); // for delay
|
||||
|
||||
setSHAR(_mac_address);
|
||||
}
|
||||
|
||||
|
||||
Wiznet5100::Wiznet5100(int8_t cs, SPIClass& spi, int8_t intr):
|
||||
_spi(spi), _cs(cs)
|
||||
{
|
||||
(void)intr;
|
||||
}
|
||||
|
||||
boolean Wiznet5100::begin(const uint8_t *mac_address)
|
||||
{
|
||||
memcpy(_mac_address, mac_address, 6);
|
||||
|
||||
pinMode(_cs, OUTPUT);
|
||||
wizchip_cs_deselect();
|
||||
|
||||
#if 0
|
||||
_spi.begin();
|
||||
_spi.setClockDivider(SPI_CLOCK_DIV4); // 4 MHz?
|
||||
_spi.setBitOrder(MSBFIRST);
|
||||
_spi.setDataMode(SPI_MODE0);
|
||||
#endif
|
||||
|
||||
wizchip_sw_reset();
|
||||
|
||||
// Set the size of the Rx and Tx buffers
|
||||
wizchip_write(RMSR, RxBufferSize);
|
||||
wizchip_write(TMSR, TxBufferSize);
|
||||
|
||||
// Set our local MAC address
|
||||
setSHAR(_mac_address);
|
||||
|
||||
// Open Socket 0 in MACRaw mode
|
||||
setSn_MR(Sn_MR_MACRAW);
|
||||
setSn_CR(Sn_CR_OPEN);
|
||||
if (getSn_SR() != SOCK_MACRAW)
|
||||
{
|
||||
// Failed to put socket 0 into MACRaw mode
|
||||
return false;
|
||||
}
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
void Wiznet5100::end()
|
||||
{
|
||||
setSn_CR(Sn_CR_CLOSE);
|
||||
|
||||
// clear all interrupt of the socket
|
||||
setSn_IR(0xFF);
|
||||
|
||||
// Wait for socket to change to closed
|
||||
while (getSn_SR() != SOCK_CLOSED);
|
||||
}
|
||||
|
||||
uint16_t Wiznet5100::readFrame(uint8_t *buffer, uint16_t bufsize)
|
||||
{
|
||||
uint16_t data_len = readFrameSize();
|
||||
|
||||
if (data_len == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data_len > bufsize)
|
||||
{
|
||||
// Packet is bigger than buffer - drop the packet
|
||||
discardFrame(data_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return readFrameData(buffer, data_len);
|
||||
}
|
||||
|
||||
uint16_t Wiznet5100::readFrameSize()
|
||||
{
|
||||
uint16_t len = getSn_RX_RSR();
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t head[2];
|
||||
uint16_t data_len = 0;
|
||||
|
||||
wizchip_recv_data(head, 2);
|
||||
setSn_CR(Sn_CR_RECV);
|
||||
|
||||
data_len = head[0];
|
||||
data_len = (data_len << 8) + head[1];
|
||||
data_len -= 2;
|
||||
|
||||
return data_len;
|
||||
}
|
||||
|
||||
void Wiznet5100::discardFrame(uint16_t framesize)
|
||||
{
|
||||
wizchip_recv_ignore(framesize);
|
||||
setSn_CR(Sn_CR_RECV);
|
||||
}
|
||||
|
||||
uint16_t Wiznet5100::readFrameData(uint8_t *buffer, uint16_t framesize)
|
||||
{
|
||||
wizchip_recv_data(buffer, framesize);
|
||||
setSn_CR(Sn_CR_RECV);
|
||||
|
||||
#if 1
|
||||
// let lwIP deal with mac address filtering
|
||||
return framesize;
|
||||
#else
|
||||
// W5100 doesn't have any built-in MAC address filtering
|
||||
if ((buffer[0] & 0x01) || memcmp(&buffer[0], _mac_address, 6) == 0)
|
||||
{
|
||||
// Addressed to an Ethernet multicast address or our unicast address
|
||||
return framesize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t Wiznet5100::sendFrame(const uint8_t *buf, uint16_t len)
|
||||
{
|
||||
// Wait for space in the transmit buffer
|
||||
while (1)
|
||||
{
|
||||
uint16_t freesize = getSn_TX_FSR();
|
||||
if (getSn_SR() == SOCK_CLOSED)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (len <= freesize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
wizchip_send_data(buf, len);
|
||||
setSn_CR(Sn_CR_SEND);
|
||||
|
||||
while (1)
|
||||
{
|
||||
uint8_t tmp = getSn_IR();
|
||||
if (tmp & Sn_IR_SENDOK)
|
||||
{
|
||||
setSn_IR(Sn_IR_SENDOK);
|
||||
// Packet sent ok
|
||||
break;
|
||||
}
|
||||
else if (tmp & Sn_IR_TIMEOUT)
|
||||
{
|
||||
setSn_IR(Sn_IR_TIMEOUT);
|
||||
// There was a timeout
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
499
libraries/lwIP_w5100/src/utility/w5100.h
Normal file
499
libraries/lwIP_w5100/src/utility/w5100.h
Normal file
@ -0,0 +1,499 @@
|
||||
/*
|
||||
Copyright (c) 2013, WIZnet Co., Ltd.
|
||||
Copyright (c) 2016, Nicholas Humfrey
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// original sources: https://github.com/njh/W5100MacRaw
|
||||
|
||||
#ifndef W5100_H
|
||||
#define W5100_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
|
||||
|
||||
class Wiznet5100
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
Constructor that uses the default hardware SPI pins
|
||||
@param cs the Arduino Chip Select / Slave Select pin (default 10)
|
||||
*/
|
||||
Wiznet5100(int8_t cs = SS, SPIClass& spi = SPI, int8_t intr = -1);
|
||||
|
||||
/**
|
||||
Initialise the Ethernet controller
|
||||
Must be called before sending or receiving Ethernet frames
|
||||
|
||||
@param address the local MAC address for the Ethernet interface
|
||||
@return Returns true if setting up the Ethernet interface was successful
|
||||
*/
|
||||
boolean begin(const uint8_t *address);
|
||||
|
||||
/**
|
||||
Shut down the Ethernet controlled
|
||||
*/
|
||||
void end();
|
||||
|
||||
/**
|
||||
Send an Ethernet frame
|
||||
@param data a pointer to the data to send
|
||||
@param datalen the length of the data in the packet
|
||||
@return the number of bytes transmitted
|
||||
*/
|
||||
uint16_t sendFrame(const uint8_t *data, uint16_t datalen);
|
||||
|
||||
/**
|
||||
Read an Ethernet frame
|
||||
@param buffer a pointer to a buffer to write the packet to
|
||||
@param bufsize the available space in the buffer
|
||||
@return the length of the received packet
|
||||
or 0 if no packet was received
|
||||
*/
|
||||
uint16_t readFrame(uint8_t *buffer, uint16_t bufsize);
|
||||
|
||||
protected:
|
||||
|
||||
static constexpr bool interruptIsPossible()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
Read an Ethernet frame size
|
||||
@return the length of data do receive
|
||||
or 0 if no frame was received
|
||||
*/
|
||||
uint16_t readFrameSize();
|
||||
|
||||
/**
|
||||
discard an Ethernet frame
|
||||
@param framesize readFrameSize()'s result
|
||||
*/
|
||||
void discardFrame(uint16_t framesize);
|
||||
|
||||
/**
|
||||
Read an Ethernet frame data
|
||||
readFrameSize() must be called first,
|
||||
its result must be passed into framesize parameter
|
||||
@param buffer a pointer to a buffer to write the frame to
|
||||
@param framesize readFrameSize()'s result
|
||||
@return the length of the received frame
|
||||
or 0 if a problem occured
|
||||
*/
|
||||
uint16_t readFrameData(uint8_t *frame, uint16_t framesize);
|
||||
|
||||
|
||||
private:
|
||||
static const uint16_t TxBufferAddress = 0x4000; /* Internal Tx buffer address of the iinchip */
|
||||
static const uint16_t RxBufferAddress = 0x6000; /* Internal Rx buffer address of the iinchip */
|
||||
static const uint8_t TxBufferSize = 0x3; /* Buffer size configuration: 0=1kb, 1=2kB, 2=4kB, 3=8kB */
|
||||
static const uint8_t RxBufferSize = 0x3; /* Buffer size configuration: 0=1kb, 1=2kB, 2=4kB, 3=8kB */
|
||||
static const uint16_t TxBufferLength = (1 << TxBufferSize) << 10; /* Length of Tx buffer in bytes */
|
||||
static const uint16_t RxBufferLength = (1 << RxBufferSize) << 10; /* Length of Rx buffer in bytes */
|
||||
static const uint16_t TxBufferMask = TxBufferLength - 1;
|
||||
static const uint16_t RxBufferMask = RxBufferLength - 1;
|
||||
|
||||
|
||||
SPIClass& _spi;
|
||||
int8_t _cs;
|
||||
uint8_t _mac_address[6];
|
||||
|
||||
/**
|
||||
Default function to select chip.
|
||||
@note This function help not to access wrong address. If you do not describe this function or register any functions,
|
||||
null function is called.
|
||||
*/
|
||||
inline void wizchip_cs_select()
|
||||
{
|
||||
digitalWrite(_cs, LOW);
|
||||
}
|
||||
|
||||
/**
|
||||
Default function to deselect chip.
|
||||
@note This function help not to access wrong address. If you do not describe this function or register any functions,
|
||||
null function is called.
|
||||
*/
|
||||
inline void wizchip_cs_deselect()
|
||||
{
|
||||
digitalWrite(_cs, HIGH);
|
||||
}
|
||||
|
||||
/**
|
||||
Read a 1 byte value from a register.
|
||||
@param address Register address
|
||||
@return The value of register
|
||||
*/
|
||||
uint8_t wizchip_read(uint16_t address);
|
||||
|
||||
/**
|
||||
Reads a 2 byte value from a register.
|
||||
@param address Register address
|
||||
@return The value of register
|
||||
*/
|
||||
uint16_t wizchip_read_word(uint16_t address);
|
||||
|
||||
/**
|
||||
It reads sequence data from registers.
|
||||
@param address Register address
|
||||
@param pBuf Pointer buffer to read data
|
||||
@param len Data length
|
||||
*/
|
||||
void wizchip_read_buf(uint16_t address, uint8_t* pBuf, uint16_t len);
|
||||
|
||||
/**
|
||||
Write a 1 byte value to a register.
|
||||
@param address Register address
|
||||
@param wb Write data
|
||||
@return void
|
||||
*/
|
||||
void wizchip_write(uint16_t address, uint8_t wb);
|
||||
|
||||
/**
|
||||
Write a 2 byte value to a register.
|
||||
@param address Register address
|
||||
@param wb Write data
|
||||
@return void
|
||||
*/
|
||||
void wizchip_write_word(uint16_t address, uint16_t word);
|
||||
|
||||
/**
|
||||
It writes sequence data to registers.
|
||||
@param address Register address
|
||||
@param pBuf Pointer buffer to write data
|
||||
@param len Data length
|
||||
*/
|
||||
void wizchip_write_buf(uint16_t address, const uint8_t* pBuf, uint16_t len);
|
||||
|
||||
|
||||
/**
|
||||
Reset WIZCHIP by softly.
|
||||
*/
|
||||
void wizchip_sw_reset(void);
|
||||
|
||||
/**
|
||||
It copies data to internal TX memory
|
||||
|
||||
@details This function reads the Tx write pointer register and after that,
|
||||
it copies the <i>wizdata(pointer buffer)</i> of the length of <i>len(variable)</i> bytes to internal TX memory
|
||||
and updates the Tx write pointer register.
|
||||
This function is being called by send() and sendto() function also.
|
||||
|
||||
@param wizdata Pointer buffer to write data
|
||||
@param len Data length
|
||||
@sa wizchip_recv_data()
|
||||
*/
|
||||
void wizchip_send_data(const uint8_t *wizdata, uint16_t len);
|
||||
|
||||
/**
|
||||
It copies data to your buffer from internal RX memory
|
||||
|
||||
@details This function read the Rx read pointer register and after that,
|
||||
it copies the received data from internal RX memory
|
||||
to <i>wizdata(pointer variable)</i> of the length of <i>len(variable)</i> bytes.
|
||||
This function is being called by recv() also.
|
||||
|
||||
@param wizdata Pointer buffer to read data
|
||||
@param len Data length
|
||||
@sa wizchip_send_data()
|
||||
*/
|
||||
void wizchip_recv_data(uint8_t *wizdata, uint16_t len);
|
||||
|
||||
/**
|
||||
It discard the received data in RX memory.
|
||||
@details It discards the data of the length of <i>len(variable)</i> bytes in internal RX memory.
|
||||
@param len Data length
|
||||
*/
|
||||
void wizchip_recv_ignore(uint16_t len);
|
||||
|
||||
/**
|
||||
Get @ref Sn_TX_FSR register
|
||||
@return uint16_t. Value of @ref Sn_TX_FSR.
|
||||
*/
|
||||
uint16_t getSn_TX_FSR();
|
||||
|
||||
/**
|
||||
Get @ref Sn_RX_RSR register
|
||||
@return uint16_t. Value of @ref Sn_RX_RSR.
|
||||
*/
|
||||
uint16_t getSn_RX_RSR();
|
||||
|
||||
|
||||
/** Common registers */
|
||||
enum
|
||||
{
|
||||
MR = 0x0000, ///< Mode Register address (R/W)
|
||||
GAR = 0x0001, ///< Gateway IP Register address (R/W)
|
||||
SUBR = 0x0005, ///< Subnet mask Register address (R/W)
|
||||
SHAR = 0x0009, ///< Source MAC Register address (R/W)
|
||||
SIPR = 0x000F, ///< Source IP Register address (R/W)
|
||||
IR = 0x0015, ///< Interrupt Register (R/W)
|
||||
IMR = 0x0016, ///< Socket Interrupt Mask Register (R/W)
|
||||
RTR = 0x0017, ///< Timeout register address (1 is 100us) (R/W)
|
||||
RCR = 0x0019, ///< Retry count register (R/W)
|
||||
RMSR = 0x001A, ///< Receive Memory Size
|
||||
TMSR = 0x001B, ///< Transmit Memory Size
|
||||
};
|
||||
|
||||
/** Socket registers */
|
||||
enum
|
||||
{
|
||||
Sn_MR = 0x0400, ///< Socket Mode register(R/W)
|
||||
Sn_CR = 0x0401, ///< Socket command register (R/W)
|
||||
Sn_IR = 0x0402, ///< Socket interrupt register (R)
|
||||
Sn_SR = 0x0403, ///< Socket status register (R)
|
||||
Sn_PORT = 0x0404, ///< Source port register (R/W)
|
||||
Sn_DHAR = 0x0406, ///< Peer MAC register address (R/W)
|
||||
Sn_DIPR = 0x040C, ///< Peer IP register address (R/W)
|
||||
Sn_DPORT = 0x0410, ///< Peer port register address (R/W)
|
||||
Sn_MSSR = 0x0412, ///< Maximum Segment Size(Sn_MSSR0) register address (R/W)
|
||||
Sn_PROTO = 0x0414, ///< IP Protocol(PROTO) Register (R/W)
|
||||
Sn_TOS = 0x0415, ///< IP Type of Service(TOS) Register (R/W)
|
||||
Sn_TTL = 0x0416, ///< IP Time to live(TTL) Register (R/W)
|
||||
Sn_TX_FSR = 0x0420, ///< Transmit free memory size register (R)
|
||||
Sn_TX_RD = 0x0422, ///< Transmit memory read pointer register address (R)
|
||||
Sn_TX_WR = 0x0424, ///< Transmit memory write pointer register address (R/W)
|
||||
Sn_RX_RSR = 0x0426, ///< Received data size register (R)
|
||||
Sn_RX_RD = 0x0428, ///< Read point of Receive memory (R/W)
|
||||
Sn_RX_WR = 0x042A, ///< Write point of Receive memory (R)
|
||||
};
|
||||
|
||||
/** Mode register values */
|
||||
enum
|
||||
{
|
||||
MR_RST = 0x80, ///< Reset
|
||||
MR_PB = 0x10, ///< Ping block
|
||||
MR_AI = 0x02, ///< Address Auto-Increment in Indirect Bus Interface
|
||||
MR_IND = 0x01, ///< Indirect Bus Interface mode
|
||||
};
|
||||
|
||||
/** Socket Mode Register values @ref Sn_MR */
|
||||
enum
|
||||
{
|
||||
Sn_MR_CLOSE = 0x00, ///< Unused socket
|
||||
Sn_MR_TCP = 0x01, ///< TCP
|
||||
Sn_MR_UDP = 0x02, ///< UDP
|
||||
Sn_MR_IPRAW = 0x03, ///< IP LAYER RAW SOCK
|
||||
Sn_MR_MACRAW = 0x04, ///< MAC LAYER RAW SOCK
|
||||
Sn_MR_ND = 0x20, ///< No Delayed Ack(TCP) flag
|
||||
Sn_MR_MF = 0x40, ///< Use MAC filter
|
||||
Sn_MR_MULTI = 0x80, ///< support multicating
|
||||
};
|
||||
|
||||
/** Socket Command Register values */
|
||||
enum
|
||||
{
|
||||
Sn_CR_OPEN = 0x01, ///< Initialise or open socket
|
||||
Sn_CR_CLOSE = 0x10, ///< Close socket
|
||||
Sn_CR_SEND = 0x20, ///< Update TX buffer pointer and send data
|
||||
Sn_CR_SEND_MAC = 0x21, ///< Send data with MAC address, so without ARP process
|
||||
Sn_CR_SEND_KEEP = 0x22, ///< Send keep alive message
|
||||
Sn_CR_RECV = 0x40, ///< Update RX buffer pointer and receive data
|
||||
};
|
||||
|
||||
/** Socket Interrupt register values */
|
||||
enum
|
||||
{
|
||||
Sn_IR_CON = 0x01, ///< CON Interrupt
|
||||
Sn_IR_DISCON = 0x02, ///< DISCON Interrupt
|
||||
Sn_IR_RECV = 0x04, ///< RECV Interrupt
|
||||
Sn_IR_TIMEOUT = 0x08, ///< TIMEOUT Interrupt
|
||||
Sn_IR_SENDOK = 0x10, ///< SEND_OK Interrupt
|
||||
};
|
||||
|
||||
/** Socket Status Register values */
|
||||
enum
|
||||
{
|
||||
SOCK_CLOSED = 0x00, ///< Closed
|
||||
SOCK_INIT = 0x13, ///< Initiate state
|
||||
SOCK_LISTEN = 0x14, ///< Listen state
|
||||
SOCK_SYNSENT = 0x15, ///< Connection state
|
||||
SOCK_SYNRECV = 0x16, ///< Connection state
|
||||
SOCK_ESTABLISHED = 0x17, ///< Success to connect
|
||||
SOCK_FIN_WAIT = 0x18, ///< Closing state
|
||||
SOCK_CLOSING = 0x1A, ///< Closing state
|
||||
SOCK_TIME_WAIT = 0x1B, ///< Closing state
|
||||
SOCK_CLOSE_WAIT = 0x1C, ///< Closing state
|
||||
SOCK_LAST_ACK = 0x1D, ///< Closing state
|
||||
SOCK_UDP = 0x22, ///< UDP socket
|
||||
SOCK_IPRAW = 0x32, ///< IP raw mode socket
|
||||
SOCK_MACRAW = 0x42, ///< MAC raw mode socket
|
||||
};
|
||||
|
||||
/**
|
||||
Set Mode Register
|
||||
@param (uint8_t)mr The value to be set.
|
||||
@sa getMR()
|
||||
*/
|
||||
inline void setMR(uint8_t mode)
|
||||
{
|
||||
wizchip_write(MR, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
Get Mode Register
|
||||
@return uint8_t. The value of Mode register.
|
||||
@sa setMR()
|
||||
*/
|
||||
inline uint8_t getMR()
|
||||
{
|
||||
return wizchip_read(MR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set local MAC address
|
||||
@param (uint8_t*)shar Pointer variable to set local MAC address. It should be allocated 6 bytes.
|
||||
@sa getSHAR()
|
||||
*/
|
||||
inline void setSHAR(const uint8_t* macaddr)
|
||||
{
|
||||
wizchip_write_buf(SHAR, macaddr, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
Get local MAC address
|
||||
@param (uint8_t*)shar Pointer variable to get local MAC address. It should be allocated 6 bytes.
|
||||
@sa setSHAR()
|
||||
*/
|
||||
inline void getSHAR(uint8_t* macaddr)
|
||||
{
|
||||
wizchip_read_buf(SHAR, macaddr, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_TX_WR register
|
||||
@param (uint16_t)txwr Value to set @ref Sn_TX_WR
|
||||
@sa GetSn_TX_WR()
|
||||
*/
|
||||
inline uint16_t getSn_TX_WR()
|
||||
{
|
||||
return wizchip_read_word(Sn_TX_WR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_TX_WR register
|
||||
@param (uint16_t)txwr Value to set @ref Sn_TX_WR
|
||||
@sa GetSn_TX_WR()
|
||||
*/
|
||||
inline void setSn_TX_WR(uint16_t txwr)
|
||||
{
|
||||
wizchip_write_word(Sn_TX_WR, txwr);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_RX_RD register
|
||||
@regurn uint16_t. Value of @ref Sn_RX_RD.
|
||||
@sa setSn_RX_RD()
|
||||
*/
|
||||
inline uint16_t getSn_RX_RD()
|
||||
{
|
||||
return wizchip_read_word(Sn_RX_RD);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_RX_RD register
|
||||
@param (uint16_t)rxrd Value to set @ref Sn_RX_RD
|
||||
@sa getSn_RX_RD()
|
||||
*/
|
||||
inline void setSn_RX_RD(uint16_t rxrd)
|
||||
{
|
||||
wizchip_write_word(Sn_RX_RD, rxrd);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_MR register
|
||||
@param (uint8_t)mr Value to set @ref Sn_MR
|
||||
@sa getSn_MR()
|
||||
*/
|
||||
inline void setSn_MR(uint8_t mr)
|
||||
{
|
||||
wizchip_write(Sn_MR, mr);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_MR register
|
||||
@return uint8_t. Value of @ref Sn_MR.
|
||||
@sa setSn_MR()
|
||||
*/
|
||||
inline uint8_t getSn_MR()
|
||||
{
|
||||
return wizchip_read(Sn_MR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_CR register, then wait for the command to execute
|
||||
@param (uint8_t)cr Value to set @ref Sn_CR
|
||||
@sa getSn_CR()
|
||||
*/
|
||||
void setSn_CR(uint8_t cr);
|
||||
|
||||
/**
|
||||
Get @ref Sn_CR register
|
||||
@return uint8_t. Value of @ref Sn_CR.
|
||||
@sa setSn_CR()
|
||||
*/
|
||||
inline uint8_t getSn_CR()
|
||||
{
|
||||
return wizchip_read(Sn_CR);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_SR register
|
||||
@return uint8_t. Value of @ref Sn_SR.
|
||||
*/
|
||||
inline uint8_t getSn_SR()
|
||||
{
|
||||
return wizchip_read(Sn_SR);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_IR register
|
||||
@return uint8_t. Value of @ref Sn_IR.
|
||||
@sa setSn_IR()
|
||||
*/
|
||||
inline uint8_t getSn_IR()
|
||||
{
|
||||
return wizchip_read(Sn_IR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_IR register
|
||||
@param (uint8_t)ir Value to set @ref Sn_IR
|
||||
@sa getSn_IR()
|
||||
*/
|
||||
inline void setSn_IR(uint8_t ir)
|
||||
{
|
||||
wizchip_write(Sn_IR, ir);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // W5100_H
|
102
libraries/lwIP_w5500/examples/TCPClient/TCPClient.ino
Normal file
102
libraries/lwIP_w5500/examples/TCPClient/TCPClient.ino
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
This sketch establishes a TCP connection to a "quote of the day" service.
|
||||
It sends a "hello" message, and then prints received data.
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <W5500lwIP.h>
|
||||
//or #include <W5100lwIP.h>
|
||||
//or #include <ENC28J60lwIP.h>
|
||||
|
||||
#include <WiFiClient.h> // WiFiClient (-> TCPClient)
|
||||
#include <ESP8266WiFi.h> // ESP8266WiFiClass::preinitWiFiOff()
|
||||
|
||||
const char* host = "djxmmx.net";
|
||||
const uint16_t port = 17;
|
||||
|
||||
using TCPClient = WiFiClient;
|
||||
|
||||
#define CSPIN 16 // wemos/lolin/nodemcu D0
|
||||
Wiznet5500lwIP eth(CSPIN);
|
||||
|
||||
void preinit() {
|
||||
// (no C++ in function)
|
||||
// disable wifi
|
||||
ESP8266WiFiClass::preinitWiFiOff();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
SPI.begin();
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV4); // 4 MHz?
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
SPI.setDataMode(SPI_MODE0);
|
||||
eth.setDefault(); // use ethernet for default route
|
||||
if (!eth.begin()) {
|
||||
Serial.println("ethernet hardware not found ... sleeping");
|
||||
while (1) {
|
||||
delay(1000);
|
||||
}
|
||||
} else {
|
||||
Serial.print("connecting ethernet");
|
||||
while (!eth.connected()) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print("ethernet IP address: ");
|
||||
Serial.println(eth.localIP());
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static bool wait = false;
|
||||
|
||||
Serial.print("connecting to ");
|
||||
Serial.print(host);
|
||||
Serial.print(':');
|
||||
Serial.println(port);
|
||||
|
||||
TCPClient client;
|
||||
if (!client.connect(host, port)) {
|
||||
Serial.println("connection failed");
|
||||
delay(5000);
|
||||
return;
|
||||
}
|
||||
|
||||
// This will send a string to the server
|
||||
Serial.println("sending data to server");
|
||||
if (client.connected()) {
|
||||
client.println("hello from ESP8266");
|
||||
}
|
||||
|
||||
// wait for data to be available
|
||||
unsigned long timeout = millis();
|
||||
while (client.available() == 0) {
|
||||
if (millis() - timeout > 5000) {
|
||||
Serial.println(">>> Client Timeout !");
|
||||
client.stop();
|
||||
delay(60000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Read all the lines of the reply from server and print them to Serial
|
||||
Serial.println("receiving from remote server");
|
||||
// not testing 'client.connected()' since we do not need to send data here
|
||||
while (client.available()) {
|
||||
char ch = static_cast<char>(client.read());
|
||||
Serial.print(ch);
|
||||
}
|
||||
|
||||
// Close the connection
|
||||
Serial.println();
|
||||
Serial.println("closing connection");
|
||||
client.stop();
|
||||
|
||||
if (wait) {
|
||||
delay(300000); // execute once every 5 minutes, don't flood remote service
|
||||
}
|
||||
wait = true;
|
||||
}
|
10
libraries/lwIP_w5500/library.properties
Normal file
10
libraries/lwIP_w5500/library.properties
Normal file
@ -0,0 +1,10 @@
|
||||
name=lwIP_w5500
|
||||
version=1
|
||||
author=Nicholas Humfrey
|
||||
maintainer=esp8266/Arduino
|
||||
sentence=Ethernet driver
|
||||
paragraph=Wiznet5500 ethernet drivers for lwIP and esp8266 Arduino from https://github.com/njh/W5500MacRaw
|
||||
category=Network
|
||||
url=https://github.com/esp8266/Arduino
|
||||
architectures=esp8266
|
||||
dot_a_linkage=true
|
10
libraries/lwIP_w5500/src/W5500lwIP.h
Normal file
10
libraries/lwIP_w5500/src/W5500lwIP.h
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
#ifndef _W5500LWIP_H
|
||||
#define _W5500LWIP_H
|
||||
|
||||
#include <LwipIntfDev.h>
|
||||
#include <utility/w5500.h>
|
||||
|
||||
using Wiznet5500lwIP = LwipIntfDev<Wiznet5500>;
|
||||
|
||||
#endif // _W5500LWIP_H
|
442
libraries/lwIP_w5500/src/utility/w5500.cpp
Normal file
442
libraries/lwIP_w5500/src/utility/w5500.cpp
Normal file
@ -0,0 +1,442 @@
|
||||
/*
|
||||
Copyright (c) 2013, WIZnet Co., Ltd.
|
||||
Copyright (c) 2016, Nicholas Humfrey
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// original sources: https://github.com/njh/W5500MacRaw
|
||||
|
||||
#include <SPI.h>
|
||||
#include "w5500.h"
|
||||
|
||||
|
||||
uint8_t Wiznet5500::wizchip_read(uint8_t block, uint16_t address)
|
||||
{
|
||||
uint8_t ret;
|
||||
|
||||
wizchip_cs_select();
|
||||
|
||||
block |= AccessModeRead;
|
||||
|
||||
wizchip_spi_write_byte((address & 0xFF00) >> 8);
|
||||
wizchip_spi_write_byte((address & 0x00FF) >> 0);
|
||||
wizchip_spi_write_byte(block);
|
||||
|
||||
ret = wizchip_spi_read_byte();
|
||||
|
||||
wizchip_cs_deselect();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t Wiznet5500::wizchip_read_word(uint8_t block, uint16_t address)
|
||||
{
|
||||
return ((uint16_t)wizchip_read(block, address) << 8) + wizchip_read(block, address + 1);
|
||||
}
|
||||
|
||||
void Wiznet5500::wizchip_read_buf(uint8_t block, uint16_t address, uint8_t* pBuf, uint16_t len)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
wizchip_cs_select();
|
||||
|
||||
block |= AccessModeRead;
|
||||
|
||||
wizchip_spi_write_byte((address & 0xFF00) >> 8);
|
||||
wizchip_spi_write_byte((address & 0x00FF) >> 0);
|
||||
wizchip_spi_write_byte(block);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
pBuf[i] = wizchip_spi_read_byte();
|
||||
}
|
||||
|
||||
wizchip_cs_deselect();
|
||||
}
|
||||
|
||||
void Wiznet5500::wizchip_write(uint8_t block, uint16_t address, uint8_t wb)
|
||||
{
|
||||
wizchip_cs_select();
|
||||
|
||||
block |= AccessModeWrite;
|
||||
|
||||
wizchip_spi_write_byte((address & 0xFF00) >> 8);
|
||||
wizchip_spi_write_byte((address & 0x00FF) >> 0);
|
||||
wizchip_spi_write_byte(block);
|
||||
wizchip_spi_write_byte(wb);
|
||||
|
||||
wizchip_cs_deselect();
|
||||
}
|
||||
|
||||
void Wiznet5500::wizchip_write_word(uint8_t block, uint16_t address, uint16_t word)
|
||||
{
|
||||
wizchip_write(block, address, (uint8_t)(word >> 8));
|
||||
wizchip_write(block, address + 1, (uint8_t) word);
|
||||
}
|
||||
|
||||
void Wiznet5500::wizchip_write_buf(uint8_t block, uint16_t address, const uint8_t* pBuf, uint16_t len)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
wizchip_cs_select();
|
||||
|
||||
block |= AccessModeWrite;
|
||||
|
||||
wizchip_spi_write_byte((address & 0xFF00) >> 8);
|
||||
wizchip_spi_write_byte((address & 0x00FF) >> 0);
|
||||
wizchip_spi_write_byte(block);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
wizchip_spi_write_byte(pBuf[i]);
|
||||
}
|
||||
|
||||
wizchip_cs_deselect();
|
||||
}
|
||||
|
||||
void Wiznet5500::setSn_CR(uint8_t cr)
|
||||
{
|
||||
// Write the command to the Command Register
|
||||
wizchip_write(BlockSelectSReg, Sn_CR, cr);
|
||||
|
||||
// Now wait for the command to complete
|
||||
while (wizchip_read(BlockSelectSReg, Sn_CR));
|
||||
}
|
||||
|
||||
uint16_t Wiznet5500::getSn_TX_FSR()
|
||||
{
|
||||
uint16_t val = 0, val1 = 0;
|
||||
do
|
||||
{
|
||||
val1 = wizchip_read_word(BlockSelectSReg, Sn_TX_FSR);
|
||||
if (val1 != 0)
|
||||
{
|
||||
val = wizchip_read_word(BlockSelectSReg, Sn_TX_FSR);
|
||||
}
|
||||
} while (val != val1);
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
uint16_t Wiznet5500::getSn_RX_RSR()
|
||||
{
|
||||
uint16_t val = 0, val1 = 0;
|
||||
do
|
||||
{
|
||||
val1 = wizchip_read_word(BlockSelectSReg, Sn_RX_RSR);
|
||||
if (val1 != 0)
|
||||
{
|
||||
val = wizchip_read_word(BlockSelectSReg, Sn_RX_RSR);
|
||||
}
|
||||
} while (val != val1);
|
||||
return val;
|
||||
}
|
||||
|
||||
void Wiznet5500::wizchip_send_data(const uint8_t *wizdata, uint16_t len)
|
||||
{
|
||||
uint16_t ptr = 0;
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ptr = getSn_TX_WR();
|
||||
wizchip_write_buf(BlockSelectTxBuf, ptr, wizdata, len);
|
||||
|
||||
ptr += len;
|
||||
|
||||
setSn_TX_WR(ptr);
|
||||
}
|
||||
|
||||
void Wiznet5500::wizchip_recv_data(uint8_t *wizdata, uint16_t len)
|
||||
{
|
||||
uint16_t ptr;
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ptr = getSn_RX_RD();
|
||||
wizchip_read_buf(BlockSelectRxBuf, ptr, wizdata, len);
|
||||
ptr += len;
|
||||
|
||||
setSn_RX_RD(ptr);
|
||||
}
|
||||
|
||||
void Wiznet5500::wizchip_recv_ignore(uint16_t len)
|
||||
{
|
||||
uint16_t ptr;
|
||||
|
||||
ptr = getSn_RX_RD();
|
||||
ptr += len;
|
||||
setSn_RX_RD(ptr);
|
||||
}
|
||||
|
||||
void Wiznet5500::wizchip_sw_reset()
|
||||
{
|
||||
setMR(MR_RST);
|
||||
getMR(); // for delay
|
||||
|
||||
setSHAR(_mac_address);
|
||||
}
|
||||
|
||||
int8_t Wiznet5500::wizphy_getphylink()
|
||||
{
|
||||
int8_t tmp;
|
||||
if (getPHYCFGR() & PHYCFGR_LNK_ON)
|
||||
{
|
||||
tmp = PHY_LINK_ON;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = PHY_LINK_OFF;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int8_t Wiznet5500::wizphy_getphypmode()
|
||||
{
|
||||
int8_t tmp = 0;
|
||||
if (getPHYCFGR() & PHYCFGR_OPMDC_PDOWN)
|
||||
{
|
||||
tmp = PHY_POWER_DOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = PHY_POWER_NORM;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void Wiznet5500::wizphy_reset()
|
||||
{
|
||||
uint8_t tmp = getPHYCFGR();
|
||||
tmp &= PHYCFGR_RST;
|
||||
setPHYCFGR(tmp);
|
||||
tmp = getPHYCFGR();
|
||||
tmp |= ~PHYCFGR_RST;
|
||||
setPHYCFGR(tmp);
|
||||
}
|
||||
|
||||
int8_t Wiznet5500::wizphy_setphypmode(uint8_t pmode)
|
||||
{
|
||||
uint8_t tmp = 0;
|
||||
tmp = getPHYCFGR();
|
||||
if ((tmp & PHYCFGR_OPMD) == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
tmp &= ~PHYCFGR_OPMDC_ALLA;
|
||||
if (pmode == PHY_POWER_DOWN)
|
||||
{
|
||||
tmp |= PHYCFGR_OPMDC_PDOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp |= PHYCFGR_OPMDC_ALLA;
|
||||
}
|
||||
setPHYCFGR(tmp);
|
||||
wizphy_reset();
|
||||
tmp = getPHYCFGR();
|
||||
if (pmode == PHY_POWER_DOWN)
|
||||
{
|
||||
if (tmp & PHYCFGR_OPMDC_PDOWN)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tmp & PHYCFGR_OPMDC_ALLA)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
Wiznet5500::Wiznet5500(int8_t cs, SPIClass& spi, int8_t intr):
|
||||
_spi(spi), _cs(cs)
|
||||
{
|
||||
(void)intr;
|
||||
}
|
||||
|
||||
boolean Wiznet5500::begin(const uint8_t *mac_address)
|
||||
{
|
||||
memcpy(_mac_address, mac_address, 6);
|
||||
|
||||
pinMode(_cs, OUTPUT);
|
||||
wizchip_cs_deselect();
|
||||
|
||||
#if 0
|
||||
_spi.begin();
|
||||
_spi.setClockDivider(SPI_CLOCK_DIV4); // 4 MHz?
|
||||
_spi.setBitOrder(MSBFIRST);
|
||||
_spi.setDataMode(SPI_MODE0);
|
||||
#endif
|
||||
|
||||
wizchip_sw_reset();
|
||||
|
||||
// Use the full 16Kb of RAM for Socket 0
|
||||
setSn_RXBUF_SIZE(16);
|
||||
setSn_TXBUF_SIZE(16);
|
||||
|
||||
// Set our local MAC address
|
||||
setSHAR(_mac_address);
|
||||
|
||||
// Open Socket 0 in MACRaw mode
|
||||
setSn_MR(Sn_MR_MACRAW);
|
||||
setSn_CR(Sn_CR_OPEN);
|
||||
if (getSn_SR() != SOCK_MACRAW)
|
||||
{
|
||||
// Failed to put socket 0 into MACRaw mode
|
||||
return false;
|
||||
}
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
void Wiznet5500::end()
|
||||
{
|
||||
setSn_CR(Sn_CR_CLOSE);
|
||||
|
||||
// clear all interrupt of the socket
|
||||
setSn_IR(0xFF);
|
||||
|
||||
// Wait for socket to change to closed
|
||||
while (getSn_SR() != SOCK_CLOSED);
|
||||
}
|
||||
|
||||
uint16_t Wiznet5500::readFrame(uint8_t *buffer, uint16_t bufsize)
|
||||
{
|
||||
uint16_t data_len = readFrameSize();
|
||||
|
||||
if (data_len == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data_len > bufsize)
|
||||
{
|
||||
// Packet is bigger than buffer - drop the packet
|
||||
discardFrame(data_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return readFrameData(buffer, data_len);
|
||||
}
|
||||
|
||||
uint16_t Wiznet5500::readFrameSize()
|
||||
{
|
||||
uint16_t len = getSn_RX_RSR();
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t head[2];
|
||||
uint16_t data_len = 0;
|
||||
|
||||
wizchip_recv_data(head, 2);
|
||||
setSn_CR(Sn_CR_RECV);
|
||||
|
||||
data_len = head[0];
|
||||
data_len = (data_len << 8) + head[1];
|
||||
data_len -= 2;
|
||||
|
||||
return data_len;
|
||||
}
|
||||
|
||||
void Wiznet5500::discardFrame(uint16_t framesize)
|
||||
{
|
||||
wizchip_recv_ignore(framesize);
|
||||
setSn_CR(Sn_CR_RECV);
|
||||
}
|
||||
|
||||
uint16_t Wiznet5500::readFrameData(uint8_t *buffer, uint16_t framesize)
|
||||
{
|
||||
wizchip_recv_data(buffer, framesize);
|
||||
setSn_CR(Sn_CR_RECV);
|
||||
|
||||
#if 1
|
||||
// let lwIP deal with mac address filtering
|
||||
return framesize;
|
||||
#else
|
||||
// Had problems with W5500 MAC address filtering (the Sn_MR_MFEN option)
|
||||
// Do it in software instead:
|
||||
if ((buffer[0] & 0x01) || memcmp(&buffer[0], _mac_address, 6) == 0)
|
||||
{
|
||||
// Addressed to an Ethernet multicast address or our unicast address
|
||||
return framesize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t Wiznet5500::sendFrame(const uint8_t *buf, uint16_t len)
|
||||
{
|
||||
// Wait for space in the transmit buffer
|
||||
while (1)
|
||||
{
|
||||
uint16_t freesize = getSn_TX_FSR();
|
||||
if (getSn_SR() == SOCK_CLOSED)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (len <= freesize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
wizchip_send_data(buf, len);
|
||||
setSn_CR(Sn_CR_SEND);
|
||||
|
||||
while (1)
|
||||
{
|
||||
uint8_t tmp = getSn_IR();
|
||||
if (tmp & Sn_IR_SENDOK)
|
||||
{
|
||||
setSn_IR(Sn_IR_SENDOK);
|
||||
// Packet sent ok
|
||||
break;
|
||||
}
|
||||
else if (tmp & Sn_IR_TIMEOUT)
|
||||
{
|
||||
setSn_IR(Sn_IR_TIMEOUT);
|
||||
// There was a timeout
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
767
libraries/lwIP_w5500/src/utility/w5500.h
Normal file
767
libraries/lwIP_w5500/src/utility/w5500.h
Normal file
@ -0,0 +1,767 @@
|
||||
/*
|
||||
Copyright (c) 2013, WIZnet Co., Ltd.
|
||||
Copyright (c) 2016, Nicholas Humfrey
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// original sources: https://github.com/njh/W5500MacRaw
|
||||
|
||||
#ifndef W5500_H
|
||||
#define W5500_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
|
||||
|
||||
|
||||
class Wiznet5500
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
Constructor that uses the default hardware SPI pins
|
||||
@param cs the Arduino Chip Select / Slave Select pin (default 10)
|
||||
*/
|
||||
Wiznet5500(int8_t cs = SS, SPIClass& spi = SPI, int8_t intr = -1);
|
||||
|
||||
|
||||
/**
|
||||
Initialise the Ethernet controller
|
||||
Must be called before sending or receiving Ethernet frames
|
||||
|
||||
@param address the local MAC address for the Ethernet interface
|
||||
@return Returns true if setting up the Ethernet interface was successful
|
||||
*/
|
||||
boolean begin(const uint8_t *address);
|
||||
|
||||
/**
|
||||
Shut down the Ethernet controlled
|
||||
*/
|
||||
void end();
|
||||
|
||||
/**
|
||||
Send an Ethernet frame
|
||||
@param data a pointer to the data to send
|
||||
@param datalen the length of the data in the packet
|
||||
@return the number of bytes transmitted
|
||||
*/
|
||||
uint16_t sendFrame(const uint8_t *data, uint16_t datalen);
|
||||
|
||||
/**
|
||||
Read an Ethernet frame
|
||||
@param buffer a pointer to a buffer to write the packet to
|
||||
@param bufsize the available space in the buffer
|
||||
@return the length of the received packet
|
||||
or 0 if no packet was received
|
||||
*/
|
||||
uint16_t readFrame(uint8_t *buffer, uint16_t bufsize);
|
||||
|
||||
protected:
|
||||
|
||||
static constexpr bool interruptIsPossible()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
Read an Ethernet frame size
|
||||
@return the length of data do receive
|
||||
or 0 if no frame was received
|
||||
*/
|
||||
uint16_t readFrameSize();
|
||||
|
||||
/**
|
||||
discard an Ethernet frame
|
||||
@param framesize readFrameSize()'s result
|
||||
*/
|
||||
void discardFrame(uint16_t framesize);
|
||||
|
||||
/**
|
||||
Read an Ethernet frame data
|
||||
readFrameSize() must be called first,
|
||||
its result must be passed into framesize parameter
|
||||
@param buffer a pointer to a buffer to write the frame to
|
||||
@param framesize readFrameSize()'s result
|
||||
@return the length of the received frame
|
||||
or 0 if a problem occured
|
||||
*/
|
||||
uint16_t readFrameData(uint8_t *frame, uint16_t framesize);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
//< SPI interface Read operation in Control Phase
|
||||
static const uint8_t AccessModeRead = (0x00 << 2);
|
||||
|
||||
//< SPI interface Read operation in Control Phase
|
||||
static const uint8_t AccessModeWrite = (0x01 << 2);
|
||||
|
||||
//< Common register block in Control Phase
|
||||
static const uint8_t BlockSelectCReg = (0x00 << 3);
|
||||
|
||||
//< Socket 0 register block in Control Phase
|
||||
static const uint8_t BlockSelectSReg = (0x01 << 3);
|
||||
|
||||
//< Socket 0 Tx buffer address block
|
||||
static const uint8_t BlockSelectTxBuf = (0x02 << 3);
|
||||
|
||||
//< Socket 0 Rx buffer address block
|
||||
static const uint8_t BlockSelectRxBuf = (0x03 << 3);
|
||||
|
||||
|
||||
|
||||
SPIClass& _spi;
|
||||
int8_t _cs;
|
||||
uint8_t _mac_address[6];
|
||||
|
||||
/**
|
||||
Default function to select chip.
|
||||
@note This function help not to access wrong address. If you do not describe this function or register any functions,
|
||||
null function is called.
|
||||
*/
|
||||
inline void wizchip_cs_select()
|
||||
{
|
||||
digitalWrite(_cs, LOW);
|
||||
}
|
||||
|
||||
/**
|
||||
Default function to deselect chip.
|
||||
@note This function help not to access wrong address. If you do not describe this function or register any functions,
|
||||
null function is called.
|
||||
*/
|
||||
inline void wizchip_cs_deselect()
|
||||
{
|
||||
digitalWrite(_cs, HIGH);
|
||||
}
|
||||
|
||||
/**
|
||||
Default function to read in SPI interface.
|
||||
@note This function help not to access wrong address. If you do not describe this function or register any functions,
|
||||
null function is called.
|
||||
*/
|
||||
inline uint8_t wizchip_spi_read_byte()
|
||||
{
|
||||
return _spi.transfer(0);
|
||||
}
|
||||
|
||||
/**
|
||||
Default function to write in SPI interface.
|
||||
@note This function help not to access wrong address. If you do not describe this function or register any functions,
|
||||
null function is called.
|
||||
*/
|
||||
inline void wizchip_spi_write_byte(uint8_t wb)
|
||||
{
|
||||
_spi.transfer(wb);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Read a 1 byte value from a register.
|
||||
@param address Register address
|
||||
@return The value of register
|
||||
*/
|
||||
uint8_t wizchip_read(uint8_t block, uint16_t address);
|
||||
|
||||
/**
|
||||
Reads a 2 byte value from a register.
|
||||
@param address Register address
|
||||
@return The value of register
|
||||
*/
|
||||
uint16_t wizchip_read_word(uint8_t block, uint16_t address);
|
||||
|
||||
/**
|
||||
It reads sequence data from registers.
|
||||
@param address Register address
|
||||
@param pBuf Pointer buffer to read data
|
||||
@param len Data length
|
||||
*/
|
||||
void wizchip_read_buf(uint8_t block, uint16_t address, uint8_t* pBuf, uint16_t len);
|
||||
|
||||
/**
|
||||
Write a 1 byte value to a register.
|
||||
@param address Register address
|
||||
@param wb Write data
|
||||
@return void
|
||||
*/
|
||||
void wizchip_write(uint8_t block, uint16_t address, uint8_t wb);
|
||||
|
||||
/**
|
||||
Write a 2 byte value to a register.
|
||||
@param address Register address
|
||||
@param wb Write data
|
||||
@return void
|
||||
*/
|
||||
void wizchip_write_word(uint8_t block, uint16_t address, uint16_t word);
|
||||
|
||||
/**
|
||||
It writes sequence data to registers.
|
||||
@param address Register address
|
||||
@param pBuf Pointer buffer to write data
|
||||
@param len Data length
|
||||
*/
|
||||
void wizchip_write_buf(uint8_t block, uint16_t address, const uint8_t* pBuf, uint16_t len);
|
||||
|
||||
/**
|
||||
Get @ref Sn_TX_FSR register
|
||||
@return uint16_t. Value of @ref Sn_TX_FSR.
|
||||
*/
|
||||
uint16_t getSn_TX_FSR();
|
||||
|
||||
/**
|
||||
Get @ref Sn_RX_RSR register
|
||||
@return uint16_t. Value of @ref Sn_RX_RSR.
|
||||
*/
|
||||
uint16_t getSn_RX_RSR();
|
||||
|
||||
|
||||
/**
|
||||
Reset WIZCHIP by softly.
|
||||
*/
|
||||
void wizchip_sw_reset();
|
||||
|
||||
/**
|
||||
Get the link status of phy in WIZCHIP
|
||||
*/
|
||||
int8_t wizphy_getphylink();
|
||||
|
||||
/**
|
||||
Get the power mode of PHY in WIZCHIP
|
||||
*/
|
||||
int8_t wizphy_getphypmode();
|
||||
|
||||
/**
|
||||
Reset Phy
|
||||
*/
|
||||
void wizphy_reset();
|
||||
|
||||
/**
|
||||
set the power mode of phy inside WIZCHIP. Refer to @ref PHYCFGR in W5500, @ref PHYSTATUS in W5200
|
||||
@param pmode Settig value of power down mode.
|
||||
*/
|
||||
int8_t wizphy_setphypmode(uint8_t pmode);
|
||||
|
||||
/**
|
||||
It copies data to internal TX memory
|
||||
|
||||
@details This function reads the Tx write pointer register and after that,
|
||||
it copies the <i>wizdata(pointer buffer)</i> of the length of <i>len(variable)</i> bytes to internal TX memory
|
||||
and updates the Tx write pointer register.
|
||||
This function is being called by send() and sendto() function also.
|
||||
|
||||
@param wizdata Pointer buffer to write data
|
||||
@param len Data length
|
||||
@sa wizchip_recv_data()
|
||||
*/
|
||||
void wizchip_send_data(const uint8_t *wizdata, uint16_t len);
|
||||
|
||||
/**
|
||||
It copies data to your buffer from internal RX memory
|
||||
|
||||
@details This function read the Rx read pointer register and after that,
|
||||
it copies the received data from internal RX memory
|
||||
to <i>wizdata(pointer variable)</i> of the length of <i>len(variable)</i> bytes.
|
||||
This function is being called by recv() also.
|
||||
|
||||
@param wizdata Pointer buffer to read data
|
||||
@param len Data length
|
||||
@sa wizchip_send_data()
|
||||
*/
|
||||
void wizchip_recv_data(uint8_t *wizdata, uint16_t len);
|
||||
|
||||
/**
|
||||
It discard the received data in RX memory.
|
||||
@details It discards the data of the length of <i>len(variable)</i> bytes in internal RX memory.
|
||||
@param len Data length
|
||||
*/
|
||||
void wizchip_recv_ignore(uint16_t len);
|
||||
|
||||
|
||||
|
||||
/** Common registers */
|
||||
enum
|
||||
{
|
||||
MR = 0x0000, ///< Mode Register address (R/W)
|
||||
SHAR = 0x0009, ///< Source MAC Register address (R/W)
|
||||
INTLEVEL = 0x0013, ///< Set Interrupt low level timer register address (R/W)
|
||||
IR = 0x0015, ///< Interrupt Register (R/W)
|
||||
_IMR_ = 0x0016, ///< Interrupt mask register (R/W)
|
||||
SIR = 0x0017, ///< Socket Interrupt Register (R/W)
|
||||
SIMR = 0x0018, ///< Socket Interrupt Mask Register (R/W)
|
||||
_RTR_ = 0x0019, ///< Timeout register address (1 is 100us) (R/W)
|
||||
_RCR_ = 0x001B, ///< Retry count register (R/W)
|
||||
UIPR = 0x0028, ///< Unreachable IP register address in UDP mode (R)
|
||||
UPORTR = 0x002C, ///< Unreachable Port register address in UDP mode (R)
|
||||
PHYCFGR = 0x002E, ///< PHY Status Register (R/W)
|
||||
VERSIONR = 0x0039, ///< Chip version register address (R)
|
||||
};
|
||||
|
||||
/** Socket registers */
|
||||
enum
|
||||
{
|
||||
Sn_MR = 0x0000, ///< Socket Mode register (R/W)
|
||||
Sn_CR = 0x0001, ///< Socket command register (R/W)
|
||||
Sn_IR = 0x0002, ///< Socket interrupt register (R)
|
||||
Sn_SR = 0x0003, ///< Socket status register (R)
|
||||
Sn_PORT = 0x0004, ///< Source port register (R/W)
|
||||
Sn_DHAR = 0x0006, ///< Peer MAC register address (R/W)
|
||||
Sn_DIPR = 0x000C, ///< Peer IP register address (R/W)
|
||||
Sn_DPORT = 0x0010, ///< Peer port register address (R/W)
|
||||
Sn_MSSR = 0x0012, ///< Maximum Segment Size(Sn_MSSR0) register address (R/W)
|
||||
Sn_TOS = 0x0015, ///< IP Type of Service(TOS) Register (R/W)
|
||||
Sn_TTL = 0x0016, ///< IP Time to live(TTL) Register (R/W)
|
||||
Sn_RXBUF_SIZE = 0x001E, ///< Receive memory size register (R/W)
|
||||
Sn_TXBUF_SIZE = 0x001F, ///< Transmit memory size register (R/W)
|
||||
Sn_TX_FSR = 0x0020, ///< Transmit free memory size register (R)
|
||||
Sn_TX_RD = 0x0022, ///< Transmit memory read pointer register address (R)
|
||||
Sn_TX_WR = 0x0024, ///< Transmit memory write pointer register address (R/W)
|
||||
Sn_RX_RSR = 0x0026, ///< Received data size register (R)
|
||||
Sn_RX_RD = 0x0028, ///< Read point of Receive memory (R/W)
|
||||
Sn_RX_WR = 0x002A, ///< Write point of Receive memory (R)
|
||||
Sn_IMR = 0x002C, ///< Socket interrupt mask register (R)
|
||||
Sn_FRAG = 0x002D, ///< Fragment field value in IP header register (R/W)
|
||||
Sn_KPALVTR = 0x002F, ///< Keep Alive Timer register (R/W)
|
||||
};
|
||||
|
||||
/** Mode register values */
|
||||
enum
|
||||
{
|
||||
MR_RST = 0x80, ///< Reset
|
||||
MR_WOL = 0x20, ///< Wake on LAN
|
||||
MR_PB = 0x10, ///< Ping block
|
||||
MR_PPPOE = 0x08, ///< Enable PPPoE
|
||||
MR_FARP = 0x02, ///< Enable UDP_FORCE_ARP CHECHK
|
||||
};
|
||||
|
||||
/* Interrupt Register values */
|
||||
enum
|
||||
{
|
||||
IR_CONFLICT = 0x80, ///< Check IP conflict
|
||||
IR_UNREACH = 0x40, ///< Get the destination unreachable message in UDP sending
|
||||
IR_PPPoE = 0x20, ///< Get the PPPoE close message
|
||||
IR_MP = 0x10, ///< Get the magic packet interrupt
|
||||
};
|
||||
|
||||
/* Interrupt Mask Register values */
|
||||
enum
|
||||
{
|
||||
IM_IR7 = 0x80, ///< IP Conflict Interrupt Mask
|
||||
IM_IR6 = 0x40, ///< Destination unreachable Interrupt Mask
|
||||
IM_IR5 = 0x20, ///< PPPoE Close Interrupt Mask
|
||||
IM_IR4 = 0x10, ///< Magic Packet Interrupt Mask
|
||||
};
|
||||
|
||||
/** Socket Mode Register values @ref Sn_MR */
|
||||
enum
|
||||
{
|
||||
Sn_MR_CLOSE = 0x00, ///< Unused socket
|
||||
Sn_MR_TCP = 0x01, ///< TCP
|
||||
Sn_MR_UDP = 0x02, ///< UDP
|
||||
Sn_MR_MACRAW = 0x04, ///< MAC LAYER RAW SOCK
|
||||
Sn_MR_UCASTB = 0x10, ///< Unicast Block in UDP Multicasting
|
||||
Sn_MR_ND = 0x20, ///< No Delayed Ack(TCP), Multicast flag
|
||||
Sn_MR_BCASTB = 0x40, ///< Broadcast block in UDP Multicasting
|
||||
Sn_MR_MULTI = 0x80, ///< Support UDP Multicasting
|
||||
Sn_MR_MIP6B = 0x10, ///< IPv6 packet Blocking in @ref Sn_MR_MACRAW mode
|
||||
Sn_MR_MMB = 0x20, ///< Multicast Blocking in @ref Sn_MR_MACRAW mode
|
||||
Sn_MR_MFEN = 0x80, ///< MAC filter enable in @ref Sn_MR_MACRAW mode
|
||||
};
|
||||
|
||||
/** Socket Command Register values */
|
||||
enum
|
||||
{
|
||||
Sn_CR_OPEN = 0x01, ///< Initialise or open socket
|
||||
Sn_CR_LISTEN = 0x02, ///< Wait connection request in TCP mode (Server mode)
|
||||
Sn_CR_CONNECT = 0x04, ///< Send connection request in TCP mode (Client mode)
|
||||
Sn_CR_DISCON = 0x08, ///< Send closing request in TCP mode
|
||||
Sn_CR_CLOSE = 0x10, ///< Close socket
|
||||
Sn_CR_SEND = 0x20, ///< Update TX buffer pointer and send data
|
||||
Sn_CR_SEND_MAC = 0x21, ///< Send data with MAC address, so without ARP process
|
||||
Sn_CR_SEND_KEEP = 0x22, ///< Send keep alive message
|
||||
Sn_CR_RECV = 0x40, ///< Update RX buffer pointer and receive data
|
||||
};
|
||||
|
||||
/** Socket Interrupt register values */
|
||||
enum
|
||||
{
|
||||
Sn_IR_CON = 0x01, ///< CON Interrupt
|
||||
Sn_IR_DISCON = 0x02, ///< DISCON Interrupt
|
||||
Sn_IR_RECV = 0x04, ///< RECV Interrupt
|
||||
Sn_IR_TIMEOUT = 0x08, ///< TIMEOUT Interrupt
|
||||
Sn_IR_SENDOK = 0x10, ///< SEND_OK Interrupt
|
||||
};
|
||||
|
||||
/** Socket Status Register values */
|
||||
enum
|
||||
{
|
||||
SOCK_CLOSED = 0x00, ///< Closed
|
||||
SOCK_INIT = 0x13, ///< Initiate state
|
||||
SOCK_LISTEN = 0x14, ///< Listen state
|
||||
SOCK_SYNSENT = 0x15, ///< Connection state
|
||||
SOCK_SYNRECV = 0x16, ///< Connection state
|
||||
SOCK_ESTABLISHED = 0x17, ///< Success to connect
|
||||
SOCK_FIN_WAIT = 0x18, ///< Closing state
|
||||
SOCK_CLOSING = 0x1A, ///< Closing state
|
||||
SOCK_TIME_WAIT = 0x1B, ///< Closing state
|
||||
SOCK_CLOSE_WAIT = 0x1C, ///< Closing state
|
||||
SOCK_LAST_ACK = 0x1D, ///< Closing state
|
||||
SOCK_UDP = 0x22, ///< UDP socket
|
||||
SOCK_MACRAW = 0x42, ///< MAC raw mode socket
|
||||
};
|
||||
|
||||
|
||||
/* PHYCFGR register value */
|
||||
enum
|
||||
{
|
||||
PHYCFGR_RST = ~(1 << 7), //< For PHY reset, must operate AND mask.
|
||||
PHYCFGR_OPMD = (1 << 6), // Configre PHY with OPMDC value
|
||||
PHYCFGR_OPMDC_ALLA = (7 << 3),
|
||||
PHYCFGR_OPMDC_PDOWN = (6 << 3),
|
||||
PHYCFGR_OPMDC_NA = (5 << 3),
|
||||
PHYCFGR_OPMDC_100FA = (4 << 3),
|
||||
PHYCFGR_OPMDC_100F = (3 << 3),
|
||||
PHYCFGR_OPMDC_100H = (2 << 3),
|
||||
PHYCFGR_OPMDC_10F = (1 << 3),
|
||||
PHYCFGR_OPMDC_10H = (0 << 3),
|
||||
PHYCFGR_DPX_FULL = (1 << 2),
|
||||
PHYCFGR_DPX_HALF = (0 << 2),
|
||||
PHYCFGR_SPD_100 = (1 << 1),
|
||||
PHYCFGR_SPD_10 = (0 << 1),
|
||||
PHYCFGR_LNK_ON = (1 << 0),
|
||||
PHYCFGR_LNK_OFF = (0 << 0),
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PHY_SPEED_10 = 0, ///< Link Speed 10
|
||||
PHY_SPEED_100 = 1, ///< Link Speed 100
|
||||
PHY_DUPLEX_HALF = 0, ///< Link Half-Duplex
|
||||
PHY_DUPLEX_FULL = 1, ///< Link Full-Duplex
|
||||
PHY_LINK_OFF = 0, ///< Link Off
|
||||
PHY_LINK_ON = 1, ///< Link On
|
||||
PHY_POWER_NORM = 0, ///< PHY power normal mode
|
||||
PHY_POWER_DOWN = 1, ///< PHY power down mode
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Set Mode Register
|
||||
@param (uint8_t)mr The value to be set.
|
||||
@sa getMR()
|
||||
*/
|
||||
inline void setMR(uint8_t mode)
|
||||
{
|
||||
wizchip_write(BlockSelectCReg, MR, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
Get Mode Register
|
||||
@return uint8_t. The value of Mode register.
|
||||
@sa setMR()
|
||||
*/
|
||||
inline uint8_t getMR()
|
||||
{
|
||||
return wizchip_read(BlockSelectCReg, MR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set local MAC address
|
||||
@param (uint8_t*)shar Pointer variable to set local MAC address. It should be allocated 6 bytes.
|
||||
@sa getSHAR()
|
||||
*/
|
||||
inline void setSHAR(const uint8_t* macaddr)
|
||||
{
|
||||
wizchip_write_buf(BlockSelectCReg, SHAR, macaddr, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
Get local MAC address
|
||||
@param (uint8_t*)shar Pointer variable to get local MAC address. It should be allocated 6 bytes.
|
||||
@sa setSHAR()
|
||||
*/
|
||||
inline void getSHAR(uint8_t* macaddr)
|
||||
{
|
||||
wizchip_read_buf(BlockSelectCReg, SHAR, macaddr, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref IR register
|
||||
@param (uint8_t)ir Value to set @ref IR register.
|
||||
@sa getIR()
|
||||
*/
|
||||
inline void setIR(uint8_t ir)
|
||||
{
|
||||
wizchip_write(BlockSelectCReg, IR, (ir & 0xF0));
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref IR register
|
||||
@return uint8_t. Value of @ref IR register.
|
||||
@sa setIR()
|
||||
*/
|
||||
inline uint8_t getIR()
|
||||
{
|
||||
return wizchip_read(BlockSelectCReg, IR) & 0xF0;
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref _IMR_ register
|
||||
@param (uint8_t)imr Value to set @ref _IMR_ register.
|
||||
@sa getIMR()
|
||||
*/
|
||||
inline void setIMR(uint8_t imr)
|
||||
{
|
||||
wizchip_write(BlockSelectCReg, _IMR_, imr);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref _IMR_ register
|
||||
@return uint8_t. Value of @ref _IMR_ register.
|
||||
@sa setIMR()
|
||||
*/
|
||||
inline uint8_t getIMR()
|
||||
{
|
||||
return wizchip_read(BlockSelectCReg, _IMR_);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref PHYCFGR register
|
||||
@param (uint8_t)phycfgr Value to set @ref PHYCFGR register.
|
||||
@sa getPHYCFGR()
|
||||
*/
|
||||
inline void setPHYCFGR(uint8_t phycfgr)
|
||||
{
|
||||
wizchip_write(BlockSelectCReg, PHYCFGR, phycfgr);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref PHYCFGR register
|
||||
@return uint8_t. Value of @ref PHYCFGR register.
|
||||
@sa setPHYCFGR()
|
||||
*/
|
||||
inline uint8_t getPHYCFGR()
|
||||
{
|
||||
return wizchip_read(BlockSelectCReg, PHYCFGR);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref VERSIONR register
|
||||
@return uint8_t. Value of @ref VERSIONR register.
|
||||
*/
|
||||
inline uint8_t getVERSIONR()
|
||||
{
|
||||
return wizchip_read(BlockSelectCReg, VERSIONR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_MR register
|
||||
@param (uint8_t)mr Value to set @ref Sn_MR
|
||||
@sa getSn_MR()
|
||||
*/
|
||||
inline void setSn_MR(uint8_t mr)
|
||||
{
|
||||
wizchip_write(BlockSelectSReg, Sn_MR, mr);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_MR register
|
||||
@return uint8_t. Value of @ref Sn_MR.
|
||||
@sa setSn_MR()
|
||||
*/
|
||||
inline uint8_t getSn_MR()
|
||||
{
|
||||
return wizchip_read(BlockSelectSReg, Sn_MR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_CR register, then wait for the command to execute
|
||||
@param (uint8_t)cr Value to set @ref Sn_CR
|
||||
@sa getSn_CR()
|
||||
*/
|
||||
void setSn_CR(uint8_t cr);
|
||||
|
||||
/**
|
||||
Get @ref Sn_CR register
|
||||
@return uint8_t. Value of @ref Sn_CR.
|
||||
@sa setSn_CR()
|
||||
*/
|
||||
inline uint8_t getSn_CR()
|
||||
{
|
||||
return wizchip_read(BlockSelectSReg, Sn_CR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_IR register
|
||||
@param (uint8_t)ir Value to set @ref Sn_IR
|
||||
@sa getSn_IR()
|
||||
*/
|
||||
inline void setSn_IR(uint8_t ir)
|
||||
{
|
||||
wizchip_write(BlockSelectSReg, Sn_IR, (ir & 0x1F));
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_IR register
|
||||
@return uint8_t. Value of @ref Sn_IR.
|
||||
@sa setSn_IR()
|
||||
*/
|
||||
inline uint8_t getSn_IR()
|
||||
{
|
||||
return (wizchip_read(BlockSelectSReg, Sn_IR) & 0x1F);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_IMR register
|
||||
@param (uint8_t)imr Value to set @ref Sn_IMR
|
||||
@sa getSn_IMR()
|
||||
*/
|
||||
inline void setSn_IMR(uint8_t imr)
|
||||
{
|
||||
wizchip_write(BlockSelectSReg, Sn_IMR, (imr & 0x1F));
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_IMR register
|
||||
@return uint8_t. Value of @ref Sn_IMR.
|
||||
@sa setSn_IMR()
|
||||
*/
|
||||
inline uint8_t getSn_IMR()
|
||||
{
|
||||
return (wizchip_read(BlockSelectSReg, Sn_IMR) & 0x1F);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_SR register
|
||||
@return uint8_t. Value of @ref Sn_SR.
|
||||
*/
|
||||
inline uint8_t getSn_SR()
|
||||
{
|
||||
return wizchip_read(BlockSelectSReg, Sn_SR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_RXBUF_SIZE register
|
||||
@param (uint8_t)rxbufsize Value to set @ref Sn_RXBUF_SIZE
|
||||
@sa getSn_RXBUF_SIZE()
|
||||
*/
|
||||
inline void setSn_RXBUF_SIZE(uint8_t rxbufsize)
|
||||
{
|
||||
wizchip_write(BlockSelectSReg, Sn_RXBUF_SIZE, rxbufsize);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_RXBUF_SIZE register
|
||||
@return uint8_t. Value of @ref Sn_RXBUF_SIZE.
|
||||
@sa setSn_RXBUF_SIZE()
|
||||
*/
|
||||
inline uint8_t getSn_RXBUF_SIZE()
|
||||
{
|
||||
return wizchip_read(BlockSelectSReg, Sn_RXBUF_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_TXBUF_SIZE register
|
||||
@param (uint8_t)txbufsize Value to set @ref Sn_TXBUF_SIZE
|
||||
@sa getSn_TXBUF_SIZE()
|
||||
*/
|
||||
inline void setSn_TXBUF_SIZE(uint8_t txbufsize)
|
||||
{
|
||||
wizchip_write(BlockSelectSReg, Sn_TXBUF_SIZE, txbufsize);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_TXBUF_SIZE register
|
||||
@return uint8_t. Value of @ref Sn_TXBUF_SIZE.
|
||||
@sa setSn_TXBUF_SIZE()
|
||||
*/
|
||||
inline uint8_t getSn_TXBUF_SIZE()
|
||||
{
|
||||
return wizchip_read(BlockSelectSReg, Sn_TXBUF_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_TX_RD register
|
||||
@return uint16_t. Value of @ref Sn_TX_RD.
|
||||
*/
|
||||
inline uint16_t getSn_TX_RD()
|
||||
{
|
||||
return wizchip_read_word(BlockSelectSReg, Sn_TX_RD);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_TX_WR register
|
||||
@param (uint16_t)txwr Value to set @ref Sn_TX_WR
|
||||
@sa GetSn_TX_WR()
|
||||
*/
|
||||
inline void setSn_TX_WR(uint16_t txwr)
|
||||
{
|
||||
wizchip_write_word(BlockSelectSReg, Sn_TX_WR, txwr);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_TX_WR register
|
||||
@return uint16_t. Value of @ref Sn_TX_WR.
|
||||
@sa setSn_TX_WR()
|
||||
*/
|
||||
inline uint16_t getSn_TX_WR()
|
||||
{
|
||||
return wizchip_read_word(BlockSelectSReg, Sn_TX_WR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_RX_RD register
|
||||
@param (uint16_t)rxrd Value to set @ref Sn_RX_RD
|
||||
@sa getSn_RX_RD()
|
||||
*/
|
||||
inline void setSn_RX_RD(uint16_t rxrd)
|
||||
{
|
||||
wizchip_write_word(BlockSelectSReg, Sn_RX_RD, rxrd);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_RX_RD register
|
||||
@return uint16_t. Value of @ref Sn_RX_RD.
|
||||
@sa setSn_RX_RD()
|
||||
*/
|
||||
inline uint16_t getSn_RX_RD()
|
||||
{
|
||||
return wizchip_read_word(BlockSelectSReg, Sn_RX_RD);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_RX_WR register
|
||||
@return uint16_t. Value of @ref Sn_RX_WR.
|
||||
*/
|
||||
inline uint16_t getSn_RX_WR()
|
||||
{
|
||||
return wizchip_read_word(BlockSelectSReg, Sn_RX_WR);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // W5500_H
|
Reference in New Issue
Block a user