diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c18c29f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,51 @@ +## Contributing to NRF52_TimerInterrupt + +### Reporting Bugs + +Please report bugs in NRF52_TimerInterrupt if you find them. + +However, before reporting a bug please check through the following: + +* [Existing Open Issues](https://github.com/khoih-prog/NRF52_TimerInterrupt/issues) - someone might have already encountered this. + +If you don't find anything, please [open a new issue](https://github.com/khoih-prog/NRF52_TimerInterrupt/issues/new). + +### How to submit a bug report + +Please ensure to specify the following: + +* Arduino IDE version (e.g. 1.8.13) or Platform.io version +* `NRF52` Core Version (e.g. Adafruit NRF52 core v0.21.0) +* Contextual information (e.g. what you were trying to achieve) +* Simplest possible steps to reproduce +* Anything that might be relevant in your opinion, such as: + * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a` + * Network configuration + + +### Example + +``` +Arduino IDE version: 1.8.13 +Arduino NRF52 Core Version 0.21.0 +OS: Ubuntu 20.04 LTS +Linux xy-Inspiron-3593 5.4.0-51-generic #56-Ubuntu SMP Mon Oct 5 14:28:49 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux + +Context: +I encountered a crash while trying to use the Timer Interrupt. + +Steps to reproduce: +1. ... +2. ... +3. ... +4. ... +``` +### Sending Feature Requests + +Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful. + +There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/NRF52_TimerInterrupt/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them. + +### Sending Pull Requests + +Pull Requests with changes and fixes are also welcome! diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4a9150f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Khoi Hoang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/LibraryPatches/Ethernet/src/Ethernet.cpp b/LibraryPatches/Ethernet/src/Ethernet.cpp new file mode 100644 index 0000000..0f3db05 --- /dev/null +++ b/LibraryPatches/Ethernet/src/Ethernet.cpp @@ -0,0 +1,320 @@ +/**************************************************************************************************************************** + Ethernet.cpp + + EthernetWebServer is a library for the Ethernet shields to run WebServer + + Based on and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Built by Khoi Hoang https://github.com/khoih-prog/EthernetWebServer + Licensed under MIT license + Version: 1.0.9 + + Copyright 2018 Paul Stoffregen + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2020 Initial coding for Arduino Mega, Teensy, etc to support Ethernetx libraries + 1.0.1 K Hoang 20/02/2020 Add support to lambda functions + 1.0.2 K Hoang 20/02/2020 Add support to UIPEthernet library for ENC28J60 + 1.0.3 K Hoang 23/02/2020 Add support to SAM DUE / SAMD21 boards + 1.0.4 K Hoang 16/04/2020 Add support to SAMD51 boards + 1.0.5 K Hoang 24/04/2020 Add support to nRF52 boards, such as AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, + Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B30_ublox, etc. + More Custom Ethernet libraries supported such as Ethernet2, Ethernet3, EthernetLarge + 1.0.6 K Hoang 27/04/2020 Add support to ESP32/ESP8266 boards + 1.0.7 K Hoang 30/04/2020 Add ENC28J60 support to ESP32/ESP8266 boards + 1.0.8 K Hoang 12/05/2020 Fix W5x00 support for ESP8266 boards. + 1.0.9 K Hoang 15/05/2020 Add EthernetWrapper.h for easier W5x00 support as well as more Ethernet libs in the future. + *****************************************************************************************************************************/ + +#include +#include "Ethernet.h" +#include "utility/w5100.h" +#include "Dhcp.h" + +#define ETHERNET_DEBUG 1 + + +IPAddress EthernetClass::_dnsServerAddress; +DhcpClass* EthernetClass::_dhcp = NULL; + +// KH +void EthernetClass::setRstPin(uint8_t pinRST) +{ + _pinRST = pinRST; + pinMode(_pinRST, OUTPUT); + digitalWrite(_pinRST, HIGH); +} +void EthernetClass::setCsPin(uint8_t pinCS) +{ + _pinCS = pinCS; + W5100.setSS(pinCS); + +#if ( ETHERNET_DEBUG > 0 ) + Serial.print("Input pinCS = "); + Serial.println(pinCS); + Serial.print("_pinCS = "); + Serial.println(_pinCS); +#endif +} + +void EthernetClass::initMaxSockNum(uint8_t maxSockNum) +{ + _maxSockNum = maxSockNum; +} + +uint8_t EthernetClass::softreset() +{ + return W5100.softReset(); +} + +void EthernetClass::hardreset() +{ + if(_pinRST != 0) + { + digitalWrite(_pinRST, LOW); + delay(1); + digitalWrite(_pinRST, HIGH); + delay(150); + } +} + +int EthernetClass::begin(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) +{ + DhcpClass s_dhcp; + _dhcp = &s_dhcp; + +#if ( ETHERNET_DEBUG > 0 ) + Serial.print("_pinCS = "); + Serial.print(_pinCS); +#endif + + // Initialise the basic info + if (W5100.init() == 0) + return 0; + + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setMACAddress(mac); + W5100.setIPAddress(IPAddress(0,0,0,0).raw_address()); + SPI.endTransaction(); + + // Now try to get our config info from a DHCP server + int ret = _dhcp->beginWithDHCP(mac, timeout, responseTimeout); + if (ret == 1) + { + // We've successfully found a DHCP server and got our configuration + // info, so set things accordingly + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); + W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + SPI.endTransaction(); + _dnsServerAddress = _dhcp->getDnsServerIp(); + socketPortRand(micros()); + } + return ret; +} + +void EthernetClass::begin(uint8_t *mac, IPAddress ip) +{ + // Assume the DNS server will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress dns = ip; + dns[3] = 1; + begin(mac, ip, dns); +} + +void EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns) +{ + // Assume the gateway will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress gateway = ip; + gateway[3] = 1; + begin(mac, ip, dns, gateway); +} + +void EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway) +{ + IPAddress subnet(255, 255, 255, 0); + begin(mac, ip, dns, gateway, subnet); +} + +void EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) +{ + // Initialise the basic info + if (W5100.init() == 0) + return; + + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setMACAddress(mac); + +#if ( defined(ESP8266) || defined(ESP32) ) + W5100.setIPAddress(ip.raw_address()); + W5100.setGatewayIp(gateway.raw_address()); + W5100.setSubnetMask(subnet.raw_address()); +#elif (ARDUINO > 106 || TEENSYDUINO > 121) + W5100.setIPAddress(ip._address.bytes); + W5100.setGatewayIp(gateway._address.bytes); + W5100.setSubnetMask(subnet._address.bytes); +#else + W5100.setIPAddress(ip._address); + W5100.setGatewayIp(gateway._address); + W5100.setSubnetMask(subnet._address); +#endif + + SPI.endTransaction(); + _dnsServerAddress = dns; +} + +void EthernetClass::init(uint8_t sspin) +{ + W5100.setSS(sspin); +} + +EthernetLinkStatus EthernetClass::linkStatus() +{ + switch (W5100.getLinkStatus()) { + case UNKNOWN: return Unknown; + case LINK_ON: return LinkON; + case LINK_OFF: return LinkOFF; + default: return Unknown; + } +} + +EthernetHardwareStatus EthernetClass::hardwareStatus() +{ + switch (W5100.getChip()) { + case 51: return EthernetW5100; + case 52: return EthernetW5200; + case 55: return EthernetW5500; + default: return EthernetNoHardware; + } +} + +int EthernetClass::maintain() +{ + int rc = DHCP_CHECK_NONE; + if (_dhcp != NULL) { + // we have a pointer to dhcp, use it + rc = _dhcp->checkLease(); + switch (rc) + { + case DHCP_CHECK_NONE: + //nothing done + break; + case DHCP_CHECK_RENEW_OK: + case DHCP_CHECK_REBIND_OK: + //we might have got a new IP. + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); + W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + SPI.endTransaction(); + _dnsServerAddress = _dhcp->getDnsServerIp(); + break; + default: + //this is actually an error, it will retry though + break; + } + } + return rc; +} + + +void EthernetClass::MACAddress(uint8_t *mac_address) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getMACAddress(mac_address); + SPI.endTransaction(); +} + +IPAddress EthernetClass::localIP() +{ + IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getIPAddress(ret.raw_address()); + SPI.endTransaction(); + return ret; +} + +IPAddress EthernetClass::subnetMask() +{ + IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getSubnetMask(ret.raw_address()); + SPI.endTransaction(); + return ret; +} + +IPAddress EthernetClass::gatewayIP() +{ + IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getGatewayIp(ret.raw_address()); + SPI.endTransaction(); + return ret; +} + +void EthernetClass::setMACAddress(const uint8_t *mac_address) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setMACAddress(mac_address); + SPI.endTransaction(); +} + +void EthernetClass::setLocalIP(const IPAddress local_ip) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + IPAddress ip = local_ip; + W5100.setIPAddress(ip.raw_address()); + SPI.endTransaction(); +} + +void EthernetClass::setSubnetMask(const IPAddress subnet) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + IPAddress ip = subnet; + W5100.setSubnetMask(ip.raw_address()); + SPI.endTransaction(); +} + +void EthernetClass::setGatewayIP(const IPAddress gateway) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + IPAddress ip = gateway; + W5100.setGatewayIp(ip.raw_address()); + SPI.endTransaction(); +} + +void EthernetClass::setRetransmissionTimeout(uint16_t milliseconds) +{ + if (milliseconds > 6553) milliseconds = 6553; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setRetransmissionTime(milliseconds * 10); + SPI.endTransaction(); +} + +void EthernetClass::setRetransmissionCount(uint8_t num) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setRetransmissionCount(num); + SPI.endTransaction(); +} + +EthernetClass Ethernet; diff --git a/LibraryPatches/Ethernet/src/Ethernet.h b/LibraryPatches/Ethernet/src/Ethernet.h new file mode 100644 index 0000000..6fee77f --- /dev/null +++ b/LibraryPatches/Ethernet/src/Ethernet.h @@ -0,0 +1,366 @@ +/**************************************************************************************************************************** + Ethernet.h + + EthernetWebServer is a library for the Ethernet shields to run WebServer + + Based on and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Built by Khoi Hoang https://github.com/khoih-prog/EthernetWebServer + Licensed under MIT license + Version: 1.0.9 + + Copyright 2018 Paul Stoffregen + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2020 Initial coding for Arduino Mega, Teensy, etc to support Ethernetx libraries + 1.0.1 K Hoang 20/02/2020 Add support to lambda functions + 1.0.2 K Hoang 20/02/2020 Add support to UIPEthernet library for ENC28J60 + 1.0.3 K Hoang 23/02/2020 Add support to SAM DUE / SAMD21 boards + 1.0.4 K Hoang 16/04/2020 Add support to SAMD51 boards + 1.0.5 K Hoang 24/04/2020 Add support to nRF52 boards, such as AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, + Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B30_ublox, etc. + More Custom Ethernet libraries supported such as Ethernet2, Ethernet3, EthernetLarge + 1.0.6 K Hoang 27/04/2020 Add support to ESP32/ESP8266 boards + 1.0.7 K Hoang 30/04/2020 Add ENC28J60 support to ESP32/ESP8266 boards + 1.0.8 K Hoang 12/05/2020 Fix W5x00 support for ESP8266 boards. + 1.0.9 K Hoang 15/05/2020 Add EthernetWrapper.h for easier W5x00 support as well as more Ethernet libs in the future. + *****************************************************************************************************************************/ + +#ifndef ethernet_h_ +#define ethernet_h_ + +// All symbols exposed to Arduino sketches are contained in this header file +// +// Older versions had much of this stuff in EthernetClient.h, EthernetServer.h, +// and socket.h. Including headers in different order could cause trouble, so +// these "friend" classes are now defined in the same header file. socket.h +// was removed to avoid possible conflict with the C library header files. + + +// Configure the maximum number of sockets to support. W5100 chips can have +// up to 4 sockets. W5200 & W5500 can have up to 8 sockets. Several bytes +// of RAM are used for each socket. Reducing the maximum can save RAM, but +// you are limited to fewer simultaneous connections. +#if defined(RAMEND) && defined(RAMSTART) && ((RAMEND - RAMSTART) <= 2048) +#define MAX_SOCK_NUM 2 //Reduce MAX_SOCK_NUM to 2 from 4, to increase buffer from 2k to 4K +#else +#define MAX_SOCK_NUM 4 //Reduce MAX_SOCK_NUM to 4 from 8, to increase buffer from 2k to 4K +#endif + +// By default, each socket uses 2K buffers inside the Wiznet chip. If +// MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting +// this will use larger buffers within the Wiznet chip. Large buffers +// can really help with UDP protocols like Artnet. In theory larger +// buffers should allow faster TCP over high-latency links, but this +// does not always seem to work in practice (maybe Wiznet bugs?) +// +//KH, to increase buffer size for W5x00 to min 4K +#define ETHERNET_LARGE_BUFFERS + + +#include +#include "Client.h" +#include "Server.h" +#include "Udp.h" + +enum EthernetLinkStatus { + Unknown, + LinkON, + LinkOFF +}; + +enum EthernetHardwareStatus { + EthernetNoHardware, + EthernetW5100, + EthernetW5200, + EthernetW5500 +}; + +class EthernetUDP; +class EthernetClient; +class EthernetServer; +class DhcpClass; + +class EthernetClass { +private: + static IPAddress _dnsServerAddress; + static DhcpClass* _dhcp; +public: + // KH + uint8_t _maxSockNum; + uint8_t _pinCS; + uint8_t _pinRST; + + void setRstPin(uint8_t pinRST = 9); // for WIZ550io or USR-ES1, must set befor Ethernet.begin + void setCsPin(uint8_t pinCS = 10); // must set befor Ethernet.begin + + // Initialize with less sockets but more RX/TX Buffer + // maxSockNum = 1 Socket 0 -> RX/TX Buffer 16k + // maxSockNum = 2 Socket 0, 1 -> RX/TX Buffer 8k + // maxSockNum = 4 Socket 0...3 -> RX/TX Buffer 4k + // maxSockNum = 8 (Standard) all sockets -> RX/TX Buffer 2k + // be carefull of the MAX_SOCK_NUM, because in the moment it can't dynamicly changed + void initMaxSockNum(uint8_t maxSockNum = 8); + + uint8_t softreset(); // can set only after Ethernet.begin + void hardreset(); // You need to set the Rst pin + + // Initialise the Ethernet shield to use the provided MAC address and + // gain the rest of the configuration through DHCP. + // Returns 0 if the DHCP configuration failed, and 1 if it succeeded + int begin(uint8_t *mac, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int maintain(); + EthernetLinkStatus linkStatus(); + EthernetHardwareStatus hardwareStatus(); + + // Manual configuration + void begin(uint8_t *mac, IPAddress ip); + void begin(uint8_t *mac, IPAddress ip, IPAddress dns); + void begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway); + void begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); + void init(uint8_t sspin = 10); + + void MACAddress(uint8_t *mac_address); + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP() { return _dnsServerAddress; } + + void setMACAddress(const uint8_t *mac_address); + void setLocalIP(const IPAddress local_ip); + void setSubnetMask(const IPAddress subnet); + void setGatewayIP(const IPAddress gateway); + void setDnsServerIP(const IPAddress dns_server) { _dnsServerAddress = dns_server; } + void setRetransmissionTimeout(uint16_t milliseconds); + void setRetransmissionCount(uint8_t num); + + friend class EthernetClient; + friend class EthernetServer; + friend class EthernetUDP; +private: + // Opens a socket(TCP or UDP or IP_RAW mode) + uint8_t socketBegin(uint8_t protocol, uint16_t port); + uint8_t socketBeginMulticast(uint8_t protocol, IPAddress ip,uint16_t port); + uint8_t socketStatus(uint8_t s); + // Close socket + void socketClose(uint8_t s); + // Establish TCP connection (Active connection) + void socketConnect(uint8_t s, uint8_t * addr, uint16_t port); + // disconnect the connection + void socketDisconnect(uint8_t s); + // Establish TCP connection (Passive connection) + uint8_t socketListen(uint8_t s); + // Send data (TCP) + uint16_t socketSend(uint8_t s, const uint8_t * buf, uint16_t len); + uint16_t socketSendAvailable(uint8_t s); + // Receive data (TCP) + int socketRecv(uint8_t s, uint8_t * buf, int16_t len); + uint16_t socketRecvAvailable(uint8_t s); + uint8_t socketPeek(uint8_t s); + // sets up a UDP datagram, the data for which will be provided by one + // or more calls to bufferData and then finally sent with sendUDP. + // return true if the datagram was successfully set up, or false if there was an error + bool socketStartUDP(uint8_t s, uint8_t* addr, uint16_t port); + // copy up to len bytes of data from buf into a UDP datagram to be + // sent later by sendUDP. Allows datagrams to be built up from a series of bufferData calls. + // return Number of bytes successfully buffered + uint16_t socketBufferData(uint8_t s, uint16_t offset, const uint8_t* buf, uint16_t len); + // Send a UDP datagram built up from a sequence of startUDP followed by one or more + // calls to bufferData. + // return true if the datagram was successfully sent, or false if there was an error + bool socketSendUDP(uint8_t s); + // Initialize the "random" source port number + void socketPortRand(uint16_t n); +}; + +extern EthernetClass Ethernet; + + +#define UDP_TX_PACKET_MAX_SIZE 24 + +class EthernetUDP : public UDP { +private: + uint16_t _port; // local port to listen on + IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed + uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed + uint16_t _offset; // offset into the packet being sent + +protected: + uint8_t sockindex; + uint16_t _remaining; // remaining bytes of incoming packet yet to be processed + +public: + EthernetUDP() : sockindex(MAX_SOCK_NUM) {} // Constructor + virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t beginMulticast(IPAddress, uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop(); // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket(); + // Write a single byte into the packet + virtual size_t write(uint8_t); + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket(); + // Number of bytes remaining in the current packet + virtual int available(); + // Read a single byte from the current packet + virtual int read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(); + virtual void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() { return _remoteIP; }; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() { return _remotePort; }; + virtual uint16_t localPort() { return _port; } +}; + + + + +class EthernetClient : public Client { +public: + + EthernetClient() : sockindex(MAX_SOCK_NUM), _timeout(5000) { } + EthernetClient(uint8_t s) : sockindex(s), _timeout(5000) { } + + uint8_t status(); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual int availableForWrite(void); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool() { return sockindex < MAX_SOCK_NUM; } + virtual bool operator==(const bool value) { return bool() == value; } + virtual bool operator!=(const bool value) { return bool() != value; } + virtual bool operator==(const EthernetClient&); + virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); } + uint8_t getSocketNumber() const { return sockindex; } + virtual uint16_t localPort(); + virtual IPAddress remoteIP(); + virtual uint16_t remotePort(); + virtual void setConnectionTimeout(uint16_t timeout) { _timeout = timeout; } + + friend class EthernetServer; + + using Print::write; + +private: + uint8_t sockindex; // MAX_SOCK_NUM means client not in use + uint16_t _timeout; +}; + + +class EthernetServer : public Server { +private: + uint16_t _port; +public: + EthernetServer(uint16_t port) : _port(port) { } + EthernetClient available(); + EthernetClient accept(); + virtual void begin(); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual operator bool(); + using Print::write; + //void statusreport(); + + // TODO: make private when socket allocation moves to EthernetClass + static uint16_t server_port[MAX_SOCK_NUM]; +}; + + +class DhcpClass { +private: + uint32_t _dhcpInitialTransactionId; + uint32_t _dhcpTransactionId; + uint8_t _dhcpMacAddr[6]; +#ifdef __arm__ + uint8_t _dhcpLocalIp[4] __attribute__((aligned(4))); + uint8_t _dhcpSubnetMask[4] __attribute__((aligned(4))); + uint8_t _dhcpGatewayIp[4] __attribute__((aligned(4))); + uint8_t _dhcpDhcpServerIp[4] __attribute__((aligned(4))); + uint8_t _dhcpDnsServerIp[4] __attribute__((aligned(4))); +#else + uint8_t _dhcpLocalIp[4]; + uint8_t _dhcpSubnetMask[4]; + uint8_t _dhcpGatewayIp[4]; + uint8_t _dhcpDhcpServerIp[4]; + uint8_t _dhcpDnsServerIp[4]; +#endif + uint32_t _dhcpLeaseTime; + uint32_t _dhcpT1, _dhcpT2; + uint32_t _renewInSec; + uint32_t _rebindInSec; + unsigned long _timeout; + unsigned long _responseTimeout; + unsigned long _lastCheckLeaseMillis; + uint8_t _dhcp_state; + EthernetUDP _dhcpUdpSocket; + + int request_DHCP_lease(); + void reset_DHCP_lease(); + void presend_DHCP(); + void send_DHCP_MESSAGE(uint8_t, uint16_t); + void printByte(char *, uint8_t); + + uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId); +public: + IPAddress getLocalIp(); + IPAddress getSubnetMask(); + IPAddress getGatewayIp(); + IPAddress getDhcpServerIp(); + IPAddress getDnsServerIp(); + + int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int checkLease(); +}; + +#endif diff --git a/LibraryPatches/Ethernet/src/EthernetServer.cpp b/LibraryPatches/Ethernet/src/EthernetServer.cpp new file mode 100644 index 0000000..2f6b8fb --- /dev/null +++ b/LibraryPatches/Ethernet/src/EthernetServer.cpp @@ -0,0 +1,244 @@ +/**************************************************************************************************************************** + EthernetServer.cpp + + EthernetWebServer is a library for the Ethernet shields to run WebServer + + Based on and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Built by Khoi Hoang https://github.com/khoih-prog/EthernetWebServer + Licensed under MIT license + Version: 1.0.9 + + Copyright 2018 Paul Stoffregen + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2020 Initial coding for Arduino Mega, Teensy, etc to support Ethernetx libraries + 1.0.1 K Hoang 20/02/2020 Add support to lambda functions + 1.0.2 K Hoang 20/02/2020 Add support to UIPEthernet library for ENC28J60 + 1.0.3 K Hoang 23/02/2020 Add support to SAM DUE / SAMD21 boards + 1.0.4 K Hoang 16/04/2020 Add support to SAMD51 boards + 1.0.5 K Hoang 24/04/2020 Add support to nRF52 boards, such as AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, + Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B30_ublox, etc. + More Custom Ethernet libraries supported such as Ethernet2, Ethernet3, EthernetLarge + 1.0.6 K Hoang 27/04/2020 Add support to ESP32/ESP8266 boards + 1.0.7 K Hoang 30/04/2020 Add ENC28J60 support to ESP32/ESP8266 boards + 1.0.8 K Hoang 12/05/2020 Fix W5x00 support for ESP8266 boards. + 1.0.9 K Hoang 15/05/2020 Add EthernetWrapper.h for easier W5x00 support as well as more Ethernet libs in the future. + *****************************************************************************************************************************/ + +#include +#include "Ethernet.h" +#include "utility/w5100.h" + +uint16_t EthernetServer::server_port[MAX_SOCK_NUM]; + + +void EthernetServer::begin() +{ + uint8_t sockindex = Ethernet.socketBegin(SnMR::TCP, _port); + if (sockindex < MAX_SOCK_NUM) + { + if (Ethernet.socketListen(sockindex)) + { + server_port[sockindex] = _port; + } + else + { + Ethernet.socketDisconnect(sockindex); + } + } +} + +EthernetClient EthernetServer::available() +{ + bool listening = false; + uint8_t sockindex = MAX_SOCK_NUM; + uint8_t chip, maxindex=MAX_SOCK_NUM; + + chip = W5100.getChip(); + + if (!chip) + return EthernetClient(MAX_SOCK_NUM); + + //KH, set W5100 to max 2 sockets to increase buffer size + if (chip == 51) + { +#ifdef ETHERNET_LARGE_BUFFERS + maxindex = 2; // W5100 chip never supports more than 4 sockets +#else + maxindex = 4; // W5100 chip never supports more than 4 sockets. Original +#endif + } + + for (uint8_t i=0; i < maxindex; i++) + { + if (server_port[i] == _port) + { + uint8_t stat = Ethernet.socketStatus(i); + if (stat == SnSR::ESTABLISHED || stat == SnSR::CLOSE_WAIT) + { + if (Ethernet.socketRecvAvailable(i) > 0) + { + sockindex = i; + } + else + { + // remote host closed connection, our end still open + if (stat == SnSR::CLOSE_WAIT) + { + Ethernet.socketDisconnect(i); + // status becomes LAST_ACK for short time + } + } + } + else if (stat == SnSR::LISTEN) + { + listening = true; + } + else if (stat == SnSR::CLOSED) + { + server_port[i] = 0; + } + } + } + + if (!listening) + { + begin(); + } + + return EthernetClient(sockindex); +} + +EthernetClient EthernetServer::accept() +{ + bool listening = false; + uint8_t sockindex = MAX_SOCK_NUM; + uint8_t chip, maxindex=MAX_SOCK_NUM; + + chip = W5100.getChip(); + + if (!chip) + return EthernetClient(MAX_SOCK_NUM); + + //KH, set W5100 to max 2 sockets to increase buffer size + if (chip == 51) + { +#ifdef ETHERNET_LARGE_BUFFERS + maxindex = 2; // W5100 chip never supports more than 4 sockets +#else + maxindex = 4; // W5100 chip never supports more than 4 sockets. Original +#endif + } + + for (uint8_t i=0; i < maxindex; i++) + { + if (server_port[i] == _port) + { + uint8_t stat = Ethernet.socketStatus(i); + + if (sockindex == MAX_SOCK_NUM && (stat == SnSR::ESTABLISHED || stat == SnSR::CLOSE_WAIT)) + { + // Return the connected client even if no data received. + // Some protocols like FTP expect the server to send the + // first data. + sockindex = i; + server_port[i] = 0; // only return the client once + } + else if (stat == SnSR::LISTEN) + { + listening = true; + } + else if (stat == SnSR::CLOSED) + { + server_port[i] = 0; + } + } + } + + if (!listening) + begin(); + + return EthernetClient(sockindex); +} + +EthernetServer::operator bool() +{ + uint8_t maxindex=MAX_SOCK_NUM; + + //KH, set W5100 to max 2 sockets to increase buffer size + if (W5100.getChip() == 51) + { +#ifdef ETHERNET_LARGE_BUFFERS + maxindex = 2; // W5100 chip never supports more than 4 sockets +#else + maxindex = 4; // W5100 chip never supports more than 4 sockets. Original +#endif + } + + for (uint8_t i=0; i < maxindex; i++) + { + if (server_port[i] == _port) + { + if (Ethernet.socketStatus(i) == SnSR::LISTEN) + { + return true; // server is listening for incoming clients + } + } + } + return false; +} + +size_t EthernetServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t EthernetServer::write(const uint8_t *buffer, size_t size) +{ + uint8_t chip, maxindex=MAX_SOCK_NUM; + + chip = W5100.getChip(); + if (!chip) return 0; + + //KH, set W5100 to max 2 sockets to increase buffer size + if (chip == 51) + { +#ifdef ETHERNET_LARGE_BUFFERS + maxindex = 2; // W5100 chip never supports more than 4 sockets +#else + maxindex = 4; // W5100 chip never supports more than 4 sockets. Original +#endif + } + + available(); + + for (uint8_t i=0; i < maxindex; i++) + { + if (server_port[i] == _port) + { + if (Ethernet.socketStatus(i) == SnSR::ESTABLISHED) + { + Ethernet.socketSend(i, buffer, size); + } + } + } + return size; +} diff --git a/LibraryPatches/Ethernet/src/utility/w5100.cpp b/LibraryPatches/Ethernet/src/utility/w5100.cpp new file mode 100644 index 0000000..5cf9cf7 --- /dev/null +++ b/LibraryPatches/Ethernet/src/utility/w5100.cpp @@ -0,0 +1,711 @@ +/**************************************************************************************************************************** + w5100.cpp - Driver for W5x00 + + EthernetWebServer is a library for the Ethernet shields to run WebServer + + Based on and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Built by Khoi Hoang https://github.com/khoih-prog/EthernetWebServer + Licensed under MIT license + Version: 1.0.9 + + Copyright 2018 Paul Stoffregen + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2020 Initial coding for Arduino Mega, Teensy, etc to support Ethernetx libraries + 1.0.1 K Hoang 20/02/2020 Add support to lambda functions + 1.0.2 K Hoang 20/02/2020 Add support to UIPEthernet library for ENC28J60 + 1.0.3 K Hoang 23/02/2020 Add support to SAM DUE / SAMD21 boards + 1.0.4 K Hoang 16/04/2020 Add support to SAMD51 boards + 1.0.5 K Hoang 24/04/2020 Add support to nRF52 boards, such as AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, + Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B30_ublox, etc. + More Custom Ethernet libraries supported such as Ethernet2, Ethernet3, EthernetLarge + 1.0.6 K Hoang 27/04/2020 Add support to ESP32/ESP8266 boards + 1.0.7 K Hoang 30/04/2020 Add ENC28J60 support to ESP32/ESP8266 boards + 1.0.8 K Hoang 12/05/2020 Fix W5x00 support for ESP8266 boards. + 1.0.9 K Hoang 15/05/2020 Add EthernetWrapper.h for easier W5x00 support as well as more Ethernet libs in the future. + *****************************************************************************************************************************/ + +#include +#include "Ethernet.h" +#include "w5100.h" + +#define W5100_DEBUG 1 + +/***************************************************/ +/** Default SS pin setting **/ +/***************************************************/ + +// If variant.h or other headers specifically define the +// default SS pin for ethernet, use it. +#if defined(PIN_SPI_SS_ETHERNET_LIB) + +#define SS_PIN_DEFAULT PIN_SPI_SS_ETHERNET_LIB +//KH +#warning w5100.cpp Use PIN_SPI_SS_ETHERNET_LIB defined, change SS_PIN_DEFAULT to PIN_SPI_SS_ETHERNET_LIB + +// MKR boards default to pin 5 for MKR ETH +// Pins 8-10 are MOSI/SCK/MISO on MRK, so don't use pin 10 +#elif defined(USE_ARDUINO_MKR_PIN_LAYOUT) || defined(ARDUINO_SAMD_MKRZERO) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRFox1200) || defined(ARDUINO_SAMD_MKRGSM1400) || defined(ARDUINO_SAMD_MKRWAN1300) + +#define SS_PIN_DEFAULT 5 +//KH +#warning w5100.cpp Use MKR, change SS_PIN_DEFAULT to 5 + +// For boards using AVR, assume shields with SS on pin 10 +// will be used. This allows for Arduino Mega (where +// SS is pin 53) and Arduino Leonardo (where SS is pin 17) +// to work by default with Arduino Ethernet Shield R2 & R3. +#elif defined(__AVR__) + +#define SS_PIN_DEFAULT 10 +//KH +#warning w5100.cpp Use __AVR__, change SS_PIN_DEFAULT to 10 + +// If variant.h or other headers define these names +// use them if none of the other cases match +#elif defined(PIN_SPI_SS) + +#if defined(__SAMD21G18A__) +//10 - 2 (6 conflict) all not OK for Nano 33 IoT !!! SPI corrupted??? +#warning w5100.cpp Use __SAMD21G18A__, change SS_PIN_DEFAULT to 10 +#define SS_PIN_DEFAULT 10 +#else +#define SS_PIN_DEFAULT PIN_SPI_SS + +//KH +#warning w5100.cpp Use PIN_SPI_SS defined, change SS_PIN_DEFAULT to PIN_SPI_SS +#endif + +#elif defined(CORE_SS0_PIN) +#define SS_PIN_DEFAULT CORE_SS0_PIN + +//KH +#warning w5100.cpp Use CORE_SS0_PIN defined, change SS_PIN_DEFAULT to CORE_SS0_PIN + +//KH for ESP32 +#elif defined(ESP32) +//pin SS already defined in ESP32 as pin 5, don't use this as conflict with SPIFFS, EEPROM, etc. +// Use in GPIO22 +#warning w5100.cpp Use ESP32, change SS_PIN_DEFAULT to GPIO22, MOSI(23), MISO(19), SCK(18) +#define SS_PIN_DEFAULT 22 //SS +/////// + +//KH for ESP8266 +#elif defined(ESP8266) +//pin SS already defined in ESP8266 as pin 15. Conflict => Move to pin GPIO4 (D2) +#warning w5100.cpp Use ESP8266, change SS_PIN_DEFAULT to SS(4), MOSI(13), MISO(12), SCK(14) +#define SS_PIN_DEFAULT D2 // GPIO4, SS + +/////// + +// As a final fallback, use pin 10 +#else +#define SS_PIN_DEFAULT 10 + +//KH +#warning w5100.cpp Use fallback, change SS_PIN_DEFAULT to 10 + +#endif + +// W5100 controller instance +uint8_t W5100Class::chip = 0; +uint8_t W5100Class::CH_BASE_MSB; +uint8_t W5100Class::ss_pin = SS_PIN_DEFAULT; +#ifdef ETHERNET_LARGE_BUFFERS +uint16_t W5100Class::SSIZE = 2048; +uint16_t W5100Class::SMASK = 0x07FF; +#endif +W5100Class W5100; + +// pointers and bitmasks for optimized SS pin +#if defined(__AVR__) + volatile uint8_t * W5100Class::ss_pin_reg; + uint8_t W5100Class::ss_pin_mask; +#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__) + volatile uint8_t * W5100Class::ss_pin_reg; +#elif defined(__IMXRT1062__) + volatile uint32_t * W5100Class::ss_pin_reg; + uint32_t W5100Class::ss_pin_mask; +#elif defined(__MKL26Z64__) + volatile uint8_t * W5100Class::ss_pin_reg; + uint8_t W5100Class::ss_pin_mask; +#elif defined(__SAM3X8E__) || defined(__SAM3A8C__) || defined(__SAM3A4C__) + volatile uint32_t * W5100Class::ss_pin_reg; + uint32_t W5100Class::ss_pin_mask; +#elif defined(__PIC32MX__) + volatile uint32_t * W5100Class::ss_pin_reg; + uint32_t W5100Class::ss_pin_mask; +#elif defined(ARDUINO_ARCH_ESP8266) + volatile uint32_t * W5100Class::ss_pin_reg; + uint32_t W5100Class::ss_pin_mask; +#elif defined(__SAMD21G18A__) + volatile uint32_t * W5100Class::ss_pin_reg; + uint32_t W5100Class::ss_pin_mask; + #warning w5100.cpp Use __SAMD21G18A__ +#endif + +// KH +uint8_t W5100Class::init(uint8_t socketNumbers, uint8_t new_ss_pin) +{ + uint8_t i; + + if (initialized) return 1; + + // Many Ethernet shields have a CAT811 or similar reset chip + // connected to W5100 or W5200 chips. The W5200 will not work at + // all, and may even drive its MISO pin, until given an active low + // reset pulse! The CAT811 has a 240 ms typical pulse length, and + // a 400 ms worst case maximum pulse length. MAX811 has a worst + // case maximum 560 ms pulse length. This delay is meant to wait + // until the reset pulse is ended. If your hardware has a shorter + // reset time, this can be edited or removed. + delay(560); + + //W5100Class::ss_pin = new_ss_pin; + +#if ( W5100_DEBUG > 0 ) + //KH + Serial.print("\nW5100 init, using SS_PIN_DEFAULT = "); + Serial.print(SS_PIN_DEFAULT); + Serial.print(", new ss_pin = "); + Serial.print(new_ss_pin); + Serial.print(", W5100Class::ss_pin = "); + Serial.println(W5100Class::ss_pin); +#endif + + SPI.begin(); + + initSS(); + resetSS(); + + // From #define SPI_ETHERNET_SETTINGS SPISettings(14000000, MSBFIRST, SPI_MODE0) + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + + // Attempt W5200 detection first, because W5200 does not properly + // reset its SPI state when CS goes high (inactive). Communication + // from detecting the other chips can leave the W5200 in a state + // where it won't recover, unless given a reset pulse. + if (isW5200()) + { + CH_BASE_MSB = 0x40; +#ifdef ETHERNET_LARGE_BUFFERS +#if MAX_SOCK_NUM <= 1 + SSIZE = 16384; +#elif MAX_SOCK_NUM <= 2 + SSIZE = 8192; +#elif MAX_SOCK_NUM <= 4 + SSIZE = 4096; +#else + SSIZE = 2048; +#endif + SMASK = SSIZE - 1; +#endif + for (i=0; i> 10); + writeSnTX_SIZE(i, SSIZE >> 10); + } + for (; i<8; i++) + { + writeSnRX_SIZE(i, 0); + writeSnTX_SIZE(i, 0); + } + +#if ( W5100_DEBUG > 0 ) + Serial.print("W5100::init: W5200, SSIZE ="); + Serial.println(SSIZE); +#endif + + // Try W5500 next. Wiznet finally seems to have implemented + // SPI well with this chip. It appears to be very resilient, + // so try it after the fragile W5200 + } else if (isW5500()) + { + CH_BASE_MSB = 0x10; +#ifdef ETHERNET_LARGE_BUFFERS +#if MAX_SOCK_NUM <= 1 + SSIZE = 16384; +#elif MAX_SOCK_NUM <= 2 + SSIZE = 8192; +#elif MAX_SOCK_NUM <= 4 + SSIZE = 4096; +#else + SSIZE = 2048; +#endif + SMASK = SSIZE - 1; + for (i=0; i> 10); + writeSnTX_SIZE(i, SSIZE >> 10); + } + for (; i<8; i++) + { + writeSnRX_SIZE(i, 0); + writeSnTX_SIZE(i, 0); + } +#endif + +#if ( W5100_DEBUG > 0 ) + Serial.print("W5100::init: W5500, SSIZE ="); + Serial.println(SSIZE); +#endif + + // Try W5100 last. This simple chip uses fixed 4 byte frames + // for every 8 bit access. Terribly inefficient, but so simple + // it recovers from "hearing" unsuccessful W5100 or W5200 + // communication. W5100 is also the only chip without a VERSIONR + // register for identification, so we check this last. + } else if (isW5100()) + { + CH_BASE_MSB = 0x04; + +#ifdef ETHERNET_LARGE_BUFFERS + + #if MAX_SOCK_NUM <= 1 + SSIZE = 8192; + writeTMSR(0x03); + writeRMSR(0x03); + #else + SSIZE = 4096; + writeTMSR(0x0A); + writeRMSR(0x0A); + #endif + + SMASK = SSIZE - 1; +#else + + writeTMSR(0x55); + writeRMSR(0x55); +#endif + +#if ( W5100_DEBUG > 0 ) + Serial.print("W5100::init: W5100, SSIZE ="); + Serial.println(SSIZE); +#endif + + // No hardware seems to be present. Or it could be a W5200 + // that's heard other SPI communication if its chip select + // pin wasn't high when a SD card or other SPI chip was used. + } + else + { +#if ( W5100_DEBUG > 0 ) + Serial.println("no chip :-("); +#endif + + chip = 0; + SPI.endTransaction(); + return 0; // no known chip is responding :-( + } + + SPI.endTransaction(); + initialized = true; + return 1; // successful init +} + +// Soft reset the Wiznet chip, by writing to its MR register reset bit +uint8_t W5100Class::softReset(void) +{ + uint16_t count=0; + +#if ( W5100_DEBUG > 1 ) + Serial.println("Wiznet soft reset"); +#endif + + // write to reset bit + writeMR(0x80); + // then wait for soft reset to complete + do + { + uint8_t mr = readMR(); + +#if ( W5100_DEBUG > 2 ) + Serial.print("mr="); + Serial.println(mr, HEX); +#endif + + if (mr == 0) + return 1; + + delay(1); + } while (++count < 20); + return 0; +} + +uint8_t W5100Class::isW5100(void) +{ + chip = 51; + +#if ( W5100_DEBUG > 1 ) + Serial.println("W5100.cpp: detect W5100 chip"); +#endif + + if (!softReset()) + return 0; + + writeMR(0x10); + if (readMR() != 0x10) + return 0; + + writeMR(0x12); + if (readMR() != 0x12) + return 0; + + writeMR(0x00); + if (readMR() != 0x00) + return 0; + +#if ( W5100_DEBUG > 1 ) + Serial.println("chip is W5100"); +#endif + + return 1; +} + +uint8_t W5100Class::isW5200(void) +{ + chip = 52; + +#if ( W5100_DEBUG > 1 ) + Serial.println("W5100.cpp: detect W5200 chip"); +#endif + + if (!softReset()) + return 0; + + writeMR(0x08); + if (readMR() != 0x08) + return 0; + + writeMR(0x10); + if (readMR() != 0x10) + return 0; + + writeMR(0x00); + if (readMR() != 0x00) + return 0; + + int ver = readVERSIONR_W5200(); + +#if ( W5100_DEBUG > 1 ) + Serial.print("version="); + Serial.println(ver); +#endif + + if (ver != 3) + return 0; + +#if ( W5100_DEBUG > 1 ) + Serial.println("chip is W5200"); +#endif + + return 1; +} + +uint8_t W5100Class::isW5500(void) +{ + chip = 55; + +#if ( W5100_DEBUG > 1 ) + Serial.println("W5100.cpp: detect W5500 chip"); +#endif + + if (!softReset()) + return 0; + + writeMR(0x08); + if (readMR() != 0x08) + return 0; + + writeMR(0x10); + if (readMR() != 0x10) + return 0; + + writeMR(0x00); + if (readMR() != 0x00) + return 0; + + int ver = readVERSIONR_W5500(); + +#if ( W5100_DEBUG > 1 ) + Serial.print("version="); + Serial.println(ver); +#endif + + if (ver != 4) + return 0; + +#if ( W5100_DEBUG > 1 ) + Serial.println("chip is W5500"); +#endif + + return 1; +} + +W5100Linkstatus W5100Class::getLinkStatus() +{ + uint8_t phystatus; + + // KH + if (!initialized) return UNKNOWN; + + switch (chip) + { + case 52: + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + phystatus = readPSTATUS_W5200(); + SPI.endTransaction(); + if (phystatus & 0x20) + return LINK_ON; + + return LINK_OFF; + + case 55: + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + phystatus = readPHYCFGR_W5500(); + SPI.endTransaction(); + if (phystatus & 0x01) + return LINK_ON; + + return LINK_OFF; + + default: + return UNKNOWN; + } +} + +uint16_t W5100Class::write(uint16_t addr, const uint8_t *buf, uint16_t len) +{ + uint8_t cmd[8]; + + if (chip == 51) + { + for (uint16_t i=0; i> 8); + SPI.transfer(addr & 0xFF); + addr++; + SPI.transfer(buf[i]); + resetSS(); + } + } + else if (chip == 52) + { + setSS(); + cmd[0] = addr >> 8; + cmd[1] = addr & 0xFF; + cmd[2] = ((len >> 8) & 0x7F) | 0x80; + cmd[3] = len & 0xFF; + SPI.transfer(cmd, 4); + +#ifdef SPI_HAS_TRANSFER_BUF + SPI.transfer(buf, NULL, len); +#else + // TODO: copy 8 bytes at a time to cmd[] and block transfer + for (uint16_t i=0; i < len; i++) + { + SPI.transfer(buf[i]); + } +#endif + resetSS(); + } + else + { + // chip == 55 + setSS(); + if (addr < 0x100) + { + // common registers 00nn + cmd[0] = 0; + cmd[1] = addr & 0xFF; + cmd[2] = 0x04; + } + else if (addr < 0x8000) + { + // socket registers 10nn, 11nn, 12nn, 13nn, etc + cmd[0] = 0; + cmd[1] = addr & 0xFF; + cmd[2] = ((addr >> 3) & 0xE0) | 0x0C; + } + else if (addr < 0xC000) + { + // transmit buffers 8000-87FF, 8800-8FFF, 9000-97FF, etc + // 10## #nnn nnnn nnnn + cmd[0] = addr >> 8; + cmd[1] = addr & 0xFF; + #if defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 1 + cmd[2] = 0x14; // 16K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 2 + cmd[2] = ((addr >> 8) & 0x20) | 0x14; // 8K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 4 + cmd[2] = ((addr >> 7) & 0x60) | 0x14; // 4K buffers + #else + cmd[2] = ((addr >> 6) & 0xE0) | 0x14; // 2K buffers + #endif + } + else + { + // receive buffers + cmd[0] = addr >> 8; + cmd[1] = addr & 0xFF; + #if defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 1 + cmd[2] = 0x1C; // 16K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 2 + cmd[2] = ((addr >> 8) & 0x20) | 0x1C; // 8K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 4 + cmd[2] = ((addr >> 7) & 0x60) | 0x1C; // 4K buffers + #else + cmd[2] = ((addr >> 6) & 0xE0) | 0x1C; // 2K buffers + #endif + } + + if (len <= 5) + { + for (uint8_t i=0; i < len; i++) + { + cmd[i + 3] = buf[i]; + } + + SPI.transfer(cmd, len + 3); + } + else + { + SPI.transfer(cmd, 3); +#ifdef SPI_HAS_TRANSFER_BUF + SPI.transfer(buf, NULL, len); +#else + // TODO: copy 8 bytes at a time to cmd[] and block transfer + for (uint16_t i=0; i < len; i++) + { + SPI.transfer(buf[i]); + } +#endif + } + resetSS(); + } + return len; +} + +uint16_t W5100Class::read(uint16_t addr, uint8_t *buf, uint16_t len) +{ + uint8_t cmd[4]; + + if (chip == 51) + { + for (uint16_t i=0; i < len; i++) + { + setSS(); + #if 1 + SPI.transfer(0x0F); + SPI.transfer(addr >> 8); + SPI.transfer(addr & 0xFF); + addr++; + buf[i] = SPI.transfer(0); + #else + cmd[0] = 0x0F; + cmd[1] = addr >> 8; + cmd[2] = addr & 0xFF; + cmd[3] = 0; + SPI.transfer(cmd, 4); // TODO: why doesn't this work? + buf[i] = cmd[3]; + addr++; + #endif + resetSS(); + } + } + else if (chip == 52) + { + setSS(); + cmd[0] = addr >> 8; + cmd[1] = addr & 0xFF; + cmd[2] = (len >> 8) & 0x7F; + cmd[3] = len & 0xFF; + SPI.transfer(cmd, 4); + memset(buf, 0, len); + SPI.transfer(buf, len); + resetSS(); + } + else + { + // chip == 55 + setSS(); + + if (addr < 0x100) + { + // common registers 00nn + cmd[0] = 0; + cmd[1] = addr & 0xFF; + cmd[2] = 0x00; + } + else if (addr < 0x8000) + { + // socket registers 10nn, 11nn, 12nn, 13nn, etc + cmd[0] = 0; + cmd[1] = addr & 0xFF; + cmd[2] = ((addr >> 3) & 0xE0) | 0x08; + } + else if (addr < 0xC000) + { + // transmit buffers 8000-87FF, 8800-8FFF, 9000-97FF, etc + // 10## #nnn nnnn nnnn + cmd[0] = addr >> 8; + cmd[1] = addr & 0xFF; + #if defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 1 + cmd[2] = 0x10; // 16K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 2 + cmd[2] = ((addr >> 8) & 0x20) | 0x10; // 8K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 4 + cmd[2] = ((addr >> 7) & 0x60) | 0x10; // 4K buffers + #else + cmd[2] = ((addr >> 6) & 0xE0) | 0x10; // 2K buffers + #endif + } else + { + // receive buffers + cmd[0] = addr >> 8; + cmd[1] = addr & 0xFF; + #if defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 1 + cmd[2] = 0x18; // 16K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 2 + cmd[2] = ((addr >> 8) & 0x20) | 0x18; // 8K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 4 + cmd[2] = ((addr >> 7) & 0x60) | 0x18; // 4K buffers + #else + cmd[2] = ((addr >> 6) & 0xE0) | 0x18; // 2K buffers + #endif + } + SPI.transfer(cmd, 3); + memset(buf, 0, len); + SPI.transfer(buf, len); + resetSS(); + } + return len; +} + +void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) +{ + // Send command to socket + writeSnCR(s, _cmd); + // Wait for command to complete + while (readSnCR(s)) ; +} diff --git a/LibraryPatches/Ethernet/src/utility/w5100.h b/LibraryPatches/Ethernet/src/utility/w5100.h new file mode 100644 index 0000000..47b72d7 --- /dev/null +++ b/LibraryPatches/Ethernet/src/utility/w5100.h @@ -0,0 +1,638 @@ +/**************************************************************************************************************************** + w5100.h - Driver for W5x00 + + EthernetWebServer is a library for the Ethernet shields to run WebServer + + Based on and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Built by Khoi Hoang https://github.com/khoih-prog/EthernetWebServer + Licensed under MIT license + Version: 1.0.9 + + Copyright 2018 Paul Stoffregen + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2020 Initial coding for Arduino Mega, Teensy, etc to support Ethernetx libraries + 1.0.1 K Hoang 20/02/2020 Add support to lambda functions + 1.0.2 K Hoang 20/02/2020 Add support to UIPEthernet library for ENC28J60 + 1.0.3 K Hoang 23/02/2020 Add support to SAM DUE / SAMD21 boards + 1.0.4 K Hoang 16/04/2020 Add support to SAMD51 boards + 1.0.5 K Hoang 24/04/2020 Add support to nRF52 boards, such as AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, + Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B30_ublox, etc. + More Custom Ethernet libraries supported such as Ethernet2, Ethernet3, EthernetLarge + 1.0.6 K Hoang 27/04/2020 Add support to ESP32/ESP8266 boards + 1.0.7 K Hoang 30/04/2020 Add ENC28J60 support to ESP32/ESP8266 boards + 1.0.8 K Hoang 12/05/2020 Fix W5x00 support for ESP8266 boards. + 1.0.9 K Hoang 15/05/2020 Add EthernetWrapper.h for easier W5x00 support as well as more Ethernet libs in the future. + *****************************************************************************************************************************/ + +// w5100.h contains private W5x00 hardware "driver" level definitions +// which are not meant to be exposed to other libraries or Arduino users + +#ifndef W5100_H_INCLUDED +#define W5100_H_INCLUDED + +#include +#include + +#ifndef USE_W5100 +#define USE_W5100 false +#else +#define USE_W5100 true +#endif + +#if !USE_W5100 + +// Safe for W5200 and W5500, but also tested OK on W5100 +// Use 14MHz if you know your W5100 can't run +// Higher SPI clock results in faster transfer to hosts on a LAN +// or with very low packet latency. With ordinary internet latency, +// the TCP window size & packet loss determine your overall speed. +#warning Use 25MHz clock for W5200/W5500. Not for W5100 +#define SPI_ETHERNET_SETTINGS SPISettings(25000000, MSBFIRST, SPI_MODE0) + +#else + +// Safe for all chips but too slow +#define SPI_ETHERNET_SETTINGS SPISettings(14000000, MSBFIRST, SPI_MODE0) +#warning Use 14MHz clock for W5100/W5200/W5500. Slow. + +#endif + +// Require Ethernet.h, because we need MAX_SOCK_NUM +#ifndef ethernet_h_ +#error "Ethernet.h must be included before w5100.h" +#endif + +// Arduino 101's SPI can not run faster than 8 MHz. +#if defined(ARDUINO_ARCH_ARC32) +#undef SPI_ETHERNET_SETTINGS +#define SPI_ETHERNET_SETTINGS SPISettings(8000000, MSBFIRST, SPI_MODE0) +#endif + +// Arduino Zero can't use W5100-based shields faster than 8 MHz +// https://github.com/arduino-libraries/Ethernet/issues/37#issuecomment-408036848 +// W5500 does seem to work at 12 MHz. Delete this if only using W5500 +#if defined(__SAMD21G18A__) +#undef SPI_ETHERNET_SETTINGS +//#warning Use SAMD21 architecture SPISettings(8000000, MSBFIRST, SPI_MODE3) => IP OK +#warning Use SAMD21 architecture SPISettings(30000000, MSBFIRST, SPI_MODE3) => IP OK +// Still not working !!! Original SPI_MODE0 not OK at all +//#define SPI_ETHERNET_SETTINGS SPISettings(8000000, MSBFIRST, SPI_MODE3) +#define SPI_ETHERNET_SETTINGS SPISettings(30000000, MSBFIRST, SPI_MODE3) +#endif + +typedef uint8_t SOCKET; + +class SnMR { +public: + static const uint8_t CLOSE = 0x00; + static const uint8_t TCP = 0x21; + static const uint8_t UDP = 0x02; + static const uint8_t IPRAW = 0x03; + static const uint8_t MACRAW = 0x04; + static const uint8_t PPPOE = 0x05; + static const uint8_t ND = 0x20; + static const uint8_t MULTI = 0x80; +}; + +enum SockCMD { + Sock_OPEN = 0x01, + Sock_LISTEN = 0x02, + Sock_CONNECT = 0x04, + Sock_DISCON = 0x08, + Sock_CLOSE = 0x10, + Sock_SEND = 0x20, + Sock_SEND_MAC = 0x21, + Sock_SEND_KEEP = 0x22, + Sock_RECV = 0x40 +}; + +class SnIR { +public: + static const uint8_t SEND_OK = 0x10; + static const uint8_t TIMEOUT = 0x08; + static const uint8_t RECV = 0x04; + static const uint8_t DISCON = 0x02; + static const uint8_t CON = 0x01; +}; + +class SnSR { +public: + static const uint8_t CLOSED = 0x00; + static const uint8_t INIT = 0x13; + static const uint8_t LISTEN = 0x14; + static const uint8_t SYNSENT = 0x15; + static const uint8_t SYNRECV = 0x16; + static const uint8_t ESTABLISHED = 0x17; + static const uint8_t FIN_WAIT = 0x18; + static const uint8_t CLOSING = 0x1A; + static const uint8_t TIME_WAIT = 0x1B; + static const uint8_t CLOSE_WAIT = 0x1C; + static const uint8_t LAST_ACK = 0x1D; + static const uint8_t UDP = 0x22; + static const uint8_t IPRAW = 0x32; + static const uint8_t MACRAW = 0x42; + static const uint8_t PPPOE = 0x5F; +}; + +class IPPROTO { +public: + static const uint8_t IP = 0; + static const uint8_t ICMP = 1; + static const uint8_t IGMP = 2; + static const uint8_t GGP = 3; + static const uint8_t TCP = 6; + static const uint8_t PUP = 12; + static const uint8_t UDP = 17; + static const uint8_t IDP = 22; + static const uint8_t ND = 77; + static const uint8_t RAW = 255; +}; + +enum W5100Linkstatus { + UNKNOWN, + LINK_ON, + LINK_OFF +}; + +class W5100Class { + +public: + // KH + uint8_t init(uint8_t socketNumbers = MAX_SOCK_NUM, uint8_t new_ss_pin = 10); + + inline void setGatewayIp(const uint8_t * addr) { writeGAR(addr); } + inline void getGatewayIp(uint8_t * addr) { readGAR(addr); } + + inline void setSubnetMask(const uint8_t * addr) { writeSUBR(addr); } + inline void getSubnetMask(uint8_t * addr) { readSUBR(addr); } + + inline void setMACAddress(const uint8_t * addr) { writeSHAR(addr); } + inline void getMACAddress(uint8_t * addr) { readSHAR(addr); } + + inline void setIPAddress(const uint8_t * addr) { writeSIPR(addr); } + inline void getIPAddress(uint8_t * addr) { readSIPR(addr); } + + inline void setRetransmissionTime(uint16_t timeout) { writeRTR(timeout); } + inline void setRetransmissionCount(uint8_t retry) { writeRCR(retry); } + + static void execCmdSn(SOCKET s, SockCMD _cmd); + + + // W5100 Registers + // --------------- +//private: +public: + static uint16_t write(uint16_t addr, const uint8_t *buf, uint16_t len); + + static uint8_t write(uint16_t addr, uint8_t data) + { + return write(addr, &data, 1); + } + + static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len); + + static uint8_t read(uint16_t addr) + { + uint8_t data; + read(addr, &data, 1); + return data; + } + +#define __GP_REGISTER8(name, address) \ + static inline void write##name(uint8_t _data) { \ + write(address, _data); \ + } \ + static inline uint8_t read##name() { \ + return read(address); \ + } +#define __GP_REGISTER16(name, address) \ + static void write##name(uint16_t _data) { \ + uint8_t buf[2]; \ + buf[0] = _data >> 8; \ + buf[1] = _data & 0xFF; \ + write(address, buf, 2); \ + } \ + static uint16_t read##name() { \ + uint8_t buf[2]; \ + read(address, buf, 2); \ + return (buf[0] << 8) | buf[1]; \ + } +#define __GP_REGISTER_N(name, address, size) \ + static uint16_t write##name(const uint8_t *_buff) { \ + return write(address, _buff, size); \ + } \ + static uint16_t read##name(uint8_t *_buff) { \ + return read(address, _buff, size); \ + } + + W5100Linkstatus getLinkStatus(); + +public: + __GP_REGISTER8 (MR, 0x0000); // Mode + __GP_REGISTER_N(GAR, 0x0001, 4); // Gateway IP address + __GP_REGISTER_N(SUBR, 0x0005, 4); // Subnet mask address + __GP_REGISTER_N(SHAR, 0x0009, 6); // Source MAC address + __GP_REGISTER_N(SIPR, 0x000F, 4); // Source IP address + __GP_REGISTER8 (IR, 0x0015); // Interrupt + __GP_REGISTER8 (IMR, 0x0016); // Interrupt Mask + __GP_REGISTER16(RTR, 0x0017); // Timeout address + __GP_REGISTER8 (RCR, 0x0019); // Retry count + __GP_REGISTER8 (RMSR, 0x001A); // Receive memory size (W5100 only) + __GP_REGISTER8 (TMSR, 0x001B); // Transmit memory size (W5100 only) + __GP_REGISTER8 (PATR, 0x001C); // Authentication type address in PPPoE mode + __GP_REGISTER8 (PTIMER, 0x0028); // PPP LCP Request Timer + __GP_REGISTER8 (PMAGIC, 0x0029); // PPP LCP Magic Number + __GP_REGISTER_N(UIPR, 0x002A, 4); // Unreachable IP address in UDP mode (W5100 only) + __GP_REGISTER16(UPORT, 0x002E); // Unreachable Port address in UDP mode (W5100 only) + __GP_REGISTER8 (VERSIONR_W5200,0x001F); // Chip Version Register (W5200 only) + __GP_REGISTER8 (VERSIONR_W5500,0x0039); // Chip Version Register (W5500 only) + __GP_REGISTER8 (PSTATUS_W5200, 0x0035); // PHY Status + __GP_REGISTER8 (PHYCFGR_W5500, 0x002E); // PHY Configuration register, default: 10111xxx + + +#undef __GP_REGISTER8 +#undef __GP_REGISTER16 +#undef __GP_REGISTER_N + + // W5100 Socket registers + // ---------------------- +private: + static uint16_t CH_BASE(void) { + //if (chip == 55) return 0x1000; + //if (chip == 52) return 0x4000; + //return 0x0400; + return CH_BASE_MSB << 8; + } + static uint8_t CH_BASE_MSB; // 1 redundant byte, saves ~80 bytes code on AVR + static const uint16_t CH_SIZE = 0x0100; + + static inline uint8_t readSn(SOCKET s, uint16_t addr) + { + return read(CH_BASE() + s * CH_SIZE + addr); + } + static inline uint8_t writeSn(SOCKET s, uint16_t addr, uint8_t data) + { + return write(CH_BASE() + s * CH_SIZE + addr, data); + } + static inline uint16_t readSn(SOCKET s, uint16_t addr, uint8_t *buf, uint16_t len) + { + return read(CH_BASE() + s * CH_SIZE + addr, buf, len); + } + static inline uint16_t writeSn(SOCKET s, uint16_t addr, uint8_t *buf, uint16_t len) + { + return write(CH_BASE() + s * CH_SIZE + addr, buf, len); + } + +#define __SOCKET_REGISTER8(name, address) \ + static inline void write##name(SOCKET _s, uint8_t _data) { \ + writeSn(_s, address, _data); \ + } \ + static inline uint8_t read##name(SOCKET _s) { \ + return readSn(_s, address); \ + } +#define __SOCKET_REGISTER16(name, address) \ + static void write##name(SOCKET _s, uint16_t _data) { \ + uint8_t buf[2]; \ + buf[0] = _data >> 8; \ + buf[1] = _data & 0xFF; \ + writeSn(_s, address, buf, 2); \ + } \ + static uint16_t read##name(SOCKET _s) { \ + uint8_t buf[2]; \ + readSn(_s, address, buf, 2); \ + return (buf[0] << 8) | buf[1]; \ + } +#define __SOCKET_REGISTER_N(name, address, size) \ + static uint16_t write##name(SOCKET _s, uint8_t *_buff) { \ + return writeSn(_s, address, _buff, size); \ + } \ + static uint16_t read##name(SOCKET _s, uint8_t *_buff) { \ + return readSn(_s, address, _buff, size); \ + } + +public: + __SOCKET_REGISTER8(SnMR, 0x0000) // Mode + __SOCKET_REGISTER8(SnCR, 0x0001) // Command + __SOCKET_REGISTER8(SnIR, 0x0002) // Interrupt + __SOCKET_REGISTER8(SnSR, 0x0003) // Status + __SOCKET_REGISTER16(SnPORT, 0x0004) // Source Port + __SOCKET_REGISTER_N(SnDHAR, 0x0006, 6) // Destination Hardw Addr + __SOCKET_REGISTER_N(SnDIPR, 0x000C, 4) // Destination IP Addr + __SOCKET_REGISTER16(SnDPORT, 0x0010) // Destination Port + __SOCKET_REGISTER16(SnMSSR, 0x0012) // Max Segment Size + __SOCKET_REGISTER8(SnPROTO, 0x0014) // Protocol in IP RAW Mode + __SOCKET_REGISTER8(SnTOS, 0x0015) // IP TOS + __SOCKET_REGISTER8(SnTTL, 0x0016) // IP TTL + __SOCKET_REGISTER8(SnRX_SIZE, 0x001E) // RX Memory Size (W5200 only) + __SOCKET_REGISTER8(SnTX_SIZE, 0x001F) // RX Memory Size (W5200 only) + __SOCKET_REGISTER16(SnTX_FSR, 0x0020) // TX Free Size + __SOCKET_REGISTER16(SnTX_RD, 0x0022) // TX Read Pointer + __SOCKET_REGISTER16(SnTX_WR, 0x0024) // TX Write Pointer + __SOCKET_REGISTER16(SnRX_RSR, 0x0026) // RX Free Size + __SOCKET_REGISTER16(SnRX_RD, 0x0028) // RX Read Pointer + __SOCKET_REGISTER16(SnRX_WR, 0x002A) // RX Write Pointer (supported?) + +#undef __SOCKET_REGISTER8 +#undef __SOCKET_REGISTER16 +#undef __SOCKET_REGISTER_N + + +private: + // KH + bool initialized = false; + static uint8_t chip; + static uint8_t ss_pin; + + static uint8_t isW5100(void); + static uint8_t isW5200(void); + static uint8_t isW5500(void); + +public: + // KH + static uint8_t softReset(void); + static uint8_t getChip(void) { return chip; } +#ifdef ETHERNET_LARGE_BUFFERS + static uint16_t SSIZE; + static uint16_t SMASK; +#else + static const uint16_t SSIZE = 2048; + static const uint16_t SMASK = 0x07FF; +#endif + static uint16_t SBASE(uint8_t socknum) + { + if (chip == 51) + { + return socknum * SSIZE + 0x4000; + } + else + { + return socknum * SSIZE + 0x8000; + } + } + + static uint16_t RBASE(uint8_t socknum) + { + if (chip == 51) { + return socknum * SSIZE + 0x6000; + } + else + { + return socknum * SSIZE + 0xC000; + } + } + + static bool hasOffsetAddressMapping(void) + { + if (chip == 55) + return true; + + return false; + } + + static void setSS(uint8_t pin) { ss_pin = pin; } + +private: +#if defined(__AVR__) + +#warning Use AVR architecture + + static volatile uint8_t *ss_pin_reg; + static uint8_t ss_pin_mask; + + inline static void initSS() + { + ss_pin_reg = portOutputRegister(digitalPinToPort(ss_pin)); + ss_pin_mask = digitalPinToBitMask(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg) &= ~ss_pin_mask; + } + + inline static void resetSS() + { + *(ss_pin_reg) |= ss_pin_mask; + } +#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__) + +#warning Use MK architecture + + static volatile uint8_t *ss_pin_reg; + + inline static void initSS() + { + ss_pin_reg = portOutputRegister(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg+256) = 1; + } + + inline static void resetSS() + { + *(ss_pin_reg+128) = 1; + } +#elif defined(__IMXRT1062__) + +#warning Use Teensy architecture + + static volatile uint32_t *ss_pin_reg; + static uint32_t ss_pin_mask; + + inline static void initSS() + { + ss_pin_reg = portOutputRegister(digitalPinToPort(ss_pin)); + ss_pin_mask = digitalPinToBitMask(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg+34) = ss_pin_mask; + } + + inline static void resetSS() + { + *(ss_pin_reg+33) = ss_pin_mask; + } +#elif defined(__MKL26Z64__) + static volatile uint8_t *ss_pin_reg; + static uint8_t ss_pin_mask; + inline static void initSS() + { + ss_pin_reg = portOutputRegister(digitalPinToPort(ss_pin)); + ss_pin_mask = digitalPinToBitMask(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg+8) = ss_pin_mask; + } + + inline static void resetSS() + { + *(ss_pin_reg+4) = ss_pin_mask; + } +#elif defined(__SAM3X8E__) || defined(__SAM3A8C__) || defined(__SAM3A4C__) + +#warning Use SAM3 architecture + + static volatile uint32_t *ss_pin_reg; + static uint32_t ss_pin_mask; + + inline static void initSS() + { + ss_pin_reg = &(digitalPinToPort(ss_pin)->PIO_PER); + ss_pin_mask = digitalPinToBitMask(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg+13) = ss_pin_mask; + } + + inline static void resetSS() + { + *(ss_pin_reg+12) = ss_pin_mask; + } +#elif defined(__PIC32MX__) + static volatile uint32_t *ss_pin_reg; + static uint32_t ss_pin_mask; + + inline static void initSS() + { + ss_pin_reg = portModeRegister(digitalPinToPort(ss_pin)); + ss_pin_mask = digitalPinToBitMask(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg+8+1) = ss_pin_mask; + } + + inline static void resetSS() + { + *(ss_pin_reg+8+2) = ss_pin_mask; + } + +#elif defined(ARDUINO_ARCH_ESP8266) + +#warning Use ARDUINO_ARCH_ESP8266 architecture + + static volatile uint32_t *ss_pin_reg; + static uint32_t ss_pin_mask; + + inline static void initSS() + { + ss_pin_reg = (volatile uint32_t*)GPO; + ss_pin_mask = 1 << ss_pin; + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + GPOC = ss_pin_mask; + } + + inline static void resetSS() + { + GPOS = ss_pin_mask; + } + +#elif defined(__SAMD21G18A__) + +#warning Use SAMD21 architecture + + static volatile uint32_t *ss_pin_reg; + static uint32_t ss_pin_mask; + + inline static void initSS() + { + ss_pin_reg = portModeRegister(digitalPinToPort(ss_pin)); + ss_pin_mask = digitalPinToBitMask(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg+5) = ss_pin_mask; + } + + inline static void resetSS() + { + *(ss_pin_reg+6) = ss_pin_mask; + } +#else + +#warning Use Default architecture + + inline static void initSS() + { + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + digitalWrite(ss_pin, LOW); + } + + inline static void resetSS() + { + digitalWrite(ss_pin, HIGH); + } +#endif +}; + +extern W5100Class W5100; + +#endif + +#ifndef UTIL_H +#define UTIL_H + +#ifndef htons +#define htons(x) ( (((x)<<8)&0xFF00) | (((x)>>8)&0xFF) ) +#endif + +#ifndef ntohs +#define ntohs(x) htons(x) +#endif + +#ifndef htonl +#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ + ((x)<< 8 & 0x00FF0000UL) | \ + ((x)>> 8 & 0x0000FF00UL) | \ + ((x)>>24 & 0x000000FFUL) ) +#endif + +#ifndef ntohl +#define ntohl(x) htonl(x) +#endif + +#endif //W5100_H_INCLUDED diff --git a/LibraryPatches/Ethernet2/src/Ethernet2.cpp b/LibraryPatches/Ethernet2/src/Ethernet2.cpp new file mode 100644 index 0000000..ba24292 --- /dev/null +++ b/LibraryPatches/Ethernet2/src/Ethernet2.cpp @@ -0,0 +1,247 @@ +/* + modified 12 Aug 2013 + by Soohwan Kim (suhwan@wiznet.co.kr) + +- 10 Apr. 2015 + Added support for Arduino Ethernet Shield 2 + by Arduino.org team + + */ + +#include "Ethernet2.h" +#include "Dhcp.h" + +// XXX: don't make assumptions about the value of MAX_SOCK_NUM. +uint8_t EthernetClass::_state[MAX_SOCK_NUM] = { 0, }; +uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = { 0, }; + + + +#if defined(WIZ550io_WITH_MACADDRESS) +int EthernetClass::begin(void) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var _mac_address + //byte mac_address[6] ={0,}; + ////// + + if (_dhcp != NULL) { + delete _dhcp; + } + _dhcp = new DhcpClass(); + + // Initialise the basic info + w5500.init(w5500_cspin); + w5500.setIPAddress(IPAddress(0,0,0,0).raw_address()); + + // KH mod + w5500.getMACAddress(_mac_address); + + // Now try to get our config info from a DHCP server + int ret = _dhcp->beginWithDHCP(_mac_address); + ////// + + if(ret == 1) + { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + w5500.setIPAddress(_dhcp->getLocalIp().raw_address()); + w5500.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + w5500.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + _dnsServerAddress = _dhcp->getDnsServerIp(); + _dnsDomainName = _dhcp->getDnsDomainName(); + _hostName = _dhcp->getHostName(); + } + + return ret; +} + +void EthernetClass::begin(IPAddress local_ip) +{ + // Assume the DNS server will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress dns_server = local_ip; + dns_server[3] = 1; + begin(local_ip, dns_server); +} + +void EthernetClass::begin(IPAddress local_ip, IPAddress dns_server) +{ + // Assume the gateway will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress gateway = local_ip; + gateway[3] = 1; + begin(local_ip, dns_server, gateway); +} + +void EthernetClass::begin(IPAddress local_ip, IPAddress dns_server, IPAddress gateway) +{ + IPAddress subnet(255, 255, 255, 0); + begin(local_ip, dns_server, gateway, subnet); +} + +void EthernetClass::begin(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) +{ + w5500.init(w5500_cspin); + w5500.setIPAddress(local_ip.raw_address()); + w5500.setGatewayIp(gateway.raw_address()); + w5500.setSubnetMask(subnet.raw_address()); + _dnsServerAddress = dns_server; +} +#else +int EthernetClass::begin(uint8_t *mac_address) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac_address, sizeof(_mac_address)); + ////// + + if (_dhcp != NULL) { + delete _dhcp; + } + _dhcp = new DhcpClass(); + // Initialise the basic info + w5500.init(w5500_cspin); + w5500.setMACAddress(mac_address); + w5500.setIPAddress(IPAddress(0,0,0,0).raw_address()); + + // Now try to get our config info from a DHCP server + int ret = _dhcp->beginWithDHCP(mac_address); + if(ret == 1) + { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + w5500.setIPAddress(_dhcp->getLocalIp().raw_address()); + w5500.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + w5500.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + _dnsServerAddress = _dhcp->getDnsServerIp(); + _dnsDomainName = _dhcp->getDnsDomainName(); + _hostName = _dhcp->getHostName(); + } + + return ret; +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac_address, sizeof(_mac_address)); + ////// + + // Assume the DNS server will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress dns_server = local_ip; + dns_server[3] = 1; + begin(mac_address, local_ip, dns_server); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac_address, sizeof(_mac_address)); + ////// + + // Assume the gateway will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress gateway = local_ip; + gateway[3] = 1; + begin(mac_address, local_ip, dns_server, gateway); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac_address, sizeof(_mac_address)); + ////// + + IPAddress subnet(255, 255, 255, 0); + begin(mac_address, local_ip, dns_server, gateway, subnet); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac_address, sizeof(_mac_address)); + ////// + + w5500.init(w5500_cspin); + w5500.setMACAddress(mac_address); + w5500.setIPAddress(local_ip.raw_address()); + w5500.setGatewayIp(gateway.raw_address()); + w5500.setSubnetMask(subnet.raw_address()); + _dnsServerAddress = dns_server; +} + +#endif + +int EthernetClass::maintain(){ + int rc = DHCP_CHECK_NONE; + if(_dhcp != NULL){ + //we have a pointer to dhcp, use it + rc = _dhcp->checkLease(); + switch ( rc ){ + case DHCP_CHECK_NONE: + //nothing done + break; + case DHCP_CHECK_RENEW_OK: + case DHCP_CHECK_REBIND_OK: + //we might have got a new IP. + w5500.setIPAddress(_dhcp->getLocalIp().raw_address()); + w5500.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + w5500.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + _dnsServerAddress = _dhcp->getDnsServerIp(); + _dnsDomainName = _dhcp->getDnsDomainName(); + _hostName = _dhcp->getHostName(); + break; + default: + //this is actually a error, it will retry though + break; + } + } + return rc; +} + +IPAddress EthernetClass::localIP() +{ + IPAddress ret; + w5500.getIPAddress(ret.raw_address()); + return ret; +} + +IPAddress EthernetClass::subnetMask() +{ + IPAddress ret; + w5500.getSubnetMask(ret.raw_address()); + return ret; +} + +IPAddress EthernetClass::gatewayIP() +{ + IPAddress ret; + w5500.getGatewayIp(ret.raw_address()); + return ret; +} + +IPAddress EthernetClass::dnsServerIP() +{ + return _dnsServerAddress; +} + +char* EthernetClass::dnsDomainName(){ + return _dnsDomainName; +} + +char* EthernetClass::hostName(){ + return _hostName; +} + +EthernetClass Ethernet; diff --git a/LibraryPatches/Ethernet2/src/Ethernet2.h b/LibraryPatches/Ethernet2/src/Ethernet2.h new file mode 100644 index 0000000..79ac906 --- /dev/null +++ b/LibraryPatches/Ethernet2/src/Ethernet2.h @@ -0,0 +1,87 @@ +/* + modified 12 Aug 2013 + by Soohwan Kim (suhwan@wiznet.co.kr) + + - 10 Apr. 2015 + Added support for Arduino Ethernet Shield 2 + by Arduino.org team + + */ +#ifndef ethernet_h +#define ethernet_h + +#include +#include "utility/w5500.h" +#include "IPAddress.h" +#include "EthernetClient.h" +#include "EthernetServer.h" +#include "Dhcp.h" + + + +class EthernetClass { +private: + IPAddress _dnsServerAddress; + char* _dnsDomainName; + char* _hostName; + DhcpClass* _dhcp; + + // KH add to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + uint8_t _mac_address[6] ={0,}; + ////// + +public: + uint8_t w5500_cspin; + + static uint8_t _state[MAX_SOCK_NUM]; + static uint16_t _server_port[MAX_SOCK_NUM]; + + EthernetClass() { _dhcp = NULL; w5500_cspin = 10; } + void init(uint8_t _cspin = 10) { w5500_cspin = _cspin; } + +#if defined(WIZ550io_WITH_MACADDRESS) + // Initialize function when use the ioShield serise (included WIZ550io) + // WIZ550io has a MAC address which is written after reset. + // Default IP, Gateway and subnet address are also writen. + // so, It needs some initial time. please refer WIZ550io Datasheet in details. + int begin(void); + void begin(IPAddress local_ip); + void begin(IPAddress local_ip, IPAddress dns_server); + void begin(IPAddress local_ip, IPAddress dns_server, IPAddress gateway); + void begin(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet); +#else + // Initialize the Ethernet shield to use the provided MAC address and gain the rest of the + // configuration through DHCP. + // Returns 0 if the DHCP configuration failed, and 1 if it succeeded + int begin(uint8_t *mac_address); + void begin(uint8_t *mac_address, IPAddress local_ip); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet); + +#endif + + int maintain(); + + // KH add to have similar function to Ethernet lib + // Certainly we can use void macAddress(uint8_t mac[]) to read from W5x00. + void MACAddress(uint8_t *mac_address) + { + memcpy(mac_address, _mac_address, sizeof(_mac_address)); + } + ////// + + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP(); + char* dnsDomainName(); + char* hostName(); + + friend class EthernetClient; + friend class EthernetServer; +}; + +extern EthernetClass Ethernet; + +#endif diff --git a/LibraryPatches/Ethernet2/src/EthernetUdp2.cpp b/LibraryPatches/Ethernet2/src/EthernetUdp2.cpp new file mode 100644 index 0000000..d8671cd --- /dev/null +++ b/LibraryPatches/Ethernet2/src/EthernetUdp2.cpp @@ -0,0 +1,290 @@ +/* + * Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. + * This version only offers minimal wrapping of socket.c/socket.h + * Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/ + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + * + * - 10 Apr. 2015 + * Added support for Arduino Ethernet Shield 2 + * by Arduino.org team + */ + +#include "utility/w5500.h" +#include "utility/socket.h" +#include "Ethernet2.h" +#include "Udp.h" +#include "Dns.h" + +#define ETHERNET2_DEBUG 0 + +/* Constructor */ +EthernetUDP::EthernetUDP() : _sock(MAX_SOCK_NUM) {} + +/* Start EthernetUDP socket, listening at local port PORT */ +uint8_t EthernetUDP::begin(uint16_t port) { + if (_sock != MAX_SOCK_NUM) + return 0; + + for (int i = 0; i < MAX_SOCK_NUM; i++) { + uint8_t s = w5500.readSnSR(i); + if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) { + _sock = i; + break; + } + } + + if (_sock == MAX_SOCK_NUM) + return 0; + + _port = port; + _remaining = 0; + socket(_sock, SnMR::UDP, _port, 0); + + return 1; +} + +//KH, to add Multicast support +/* Start EthernetUDP socket, listening at local port PORT */ +uint8_t EthernetUDP::beginMulticast(IPAddress ip, uint16_t port) +{ + if (_sock != MAX_SOCK_NUM) + return 0; + + for (int i = 0; i < MAX_SOCK_NUM; i++) { + uint8_t s = w5500.readSnSR(i); + if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) { + _sock = i; + break; + } + } + + if (_sock == MAX_SOCK_NUM) + return 0; + + // Calculate MAC address from Multicast IP Address + byte mac[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 }; + + mac[3] = ip[1] & 0x7F; + mac[4] = ip[2]; + mac[5] = ip[3]; + + w5500.writeSnDIPR(_sock, rawIPAddress(ip)); //239.255.0.1 + w5500.writeSnDPORT(_sock, port); + w5500.writeSnDHAR(_sock,mac); + + _remaining = 0; + socket(_sock, SnMR::UDP, port, SnMR::MULTI); + return 1; +} +////// + + + +/* return number of bytes available in the current packet, + will return zero if parsePacket hasn't been called yet */ +int EthernetUDP::available() { + return _remaining; +} + +/* Release any resources being used by this EthernetUDP instance */ +void EthernetUDP::stop() +{ + if (_sock == MAX_SOCK_NUM) + return; + + close(_sock); + + EthernetClass::_server_port[_sock] = 0; + _sock = MAX_SOCK_NUM; +} + +int EthernetUDP::beginPacket(const char *host, uint16_t port) +{ + // Look up the host first + int ret = 0; + DNSClient dns; + IPAddress remote_addr; + + dns.begin(Ethernet.dnsServerIP()); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return beginPacket(remote_addr, port); + } else { + return ret; + } +} + +int EthernetUDP::beginPacket(IPAddress ip, uint16_t port) +{ + _offset = 0; + +// KH debug +#if (ETHERNET2_DEBUG > 1) + Serial.print("Ethernet2UDP::beginPacket: ip="); + Serial.print(ip); + Serial.print(", port="); + Serial.println(port); +#endif + + return startUDP(_sock, rawIPAddress(ip), port); +} + +int EthernetUDP::endPacket() +{ + return sendUDP(_sock); +} + +size_t EthernetUDP::write(uint8_t byte) +{ + return write(&byte, 1); +} + +size_t EthernetUDP::write(const uint8_t *buffer, size_t size) +{ + // KH debug +#if (ETHERNET2_DEBUG > 1) + Serial.print("Ethernet2UDP:write, size="); + Serial.println(size); +#endif + + uint16_t bytes_written = bufferData(_sock, _offset, buffer, size); + _offset += bytes_written; + + // KH debug +#if (ETHERNET2_DEBUG > 1) + Serial.print("Ethernet2UDP: bytes written="); + Serial.println(bytes_written); +#endif + + return bytes_written; +} + +int EthernetUDP::parsePacket() +{ + // discard any remaining bytes in the last packet + flush(); + + if (w5500.getRXReceivedSize(_sock) > 0) + { + //HACK - hand-parse the UDP packet using TCP recv method + uint8_t tmpBuf[8]; + int ret =0; + //read 8 header bytes and get IP and port from it + ret = recv(_sock,tmpBuf,8); + if (ret > 0) + { + _remoteIP = tmpBuf; + _remotePort = tmpBuf[4]; + _remotePort = (_remotePort << 8) + tmpBuf[5]; + _remaining = tmpBuf[6]; + _remaining = (_remaining << 8) + tmpBuf[7]; + + // When we get here, any remaining bytes are the data + ret = _remaining; + } + + // KH debug +#if (ETHERNET2_DEBUG > 1) + Serial.print("Ethernet2UDP:parsePacket OK, datasize="); + Serial.println(ret); +#endif + + return ret; + } + // There aren't any packets available + return 0; +} + +int EthernetUDP::read() +{ + uint8_t byte; + + if ((_remaining > 0) && (recv(_sock, &byte, 1) > 0)) + { + // We read things without any problems + _remaining--; + return byte; + } + + // If we get here, there's no data available + return -1; +} + +int EthernetUDP::read(unsigned char* buffer, size_t len) +{ + + if (_remaining > 0) + { + + int got; + + if (_remaining <= len) + { + // data should fit in the buffer + got = recv(_sock, buffer, _remaining); + } + else + { + // too much data for the buffer, + // grab as much as will fit + got = recv(_sock, buffer, len); + } + + if (got > 0) + { + _remaining -= got; + return got; + } + + } + + // If we get here, there's no data available or recv failed + return -1; + +} + +int EthernetUDP::peek() +{ + uint8_t b; + // Unlike recv, peek doesn't check to see if there's any data available, so we must. + // If the user hasn't called parsePacket yet then return nothing otherwise they + // may get the UDP header + if (!_remaining) + return -1; + ::peek(_sock, &b); + return b; +} + +void EthernetUDP::flush() +{ + // could this fail (loop endlessly) if _remaining > 0 and recv in read fails? + // should only occur if recv fails after telling us the data is there, lets + // hope the w5500 always behaves :) + + while (_remaining) + { + read(); + } +} + diff --git a/LibraryPatches/Ethernet2/src/EthernetUdp2.h b/LibraryPatches/Ethernet2/src/EthernetUdp2.h new file mode 100644 index 0000000..fe8d110 --- /dev/null +++ b/LibraryPatches/Ethernet2/src/EthernetUdp2.h @@ -0,0 +1,110 @@ +/* + * Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. + * This version only offers minimal wrapping of socket.c/socket.h + * Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/ + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + * + * - 10 Apr. 2015 + * Added support for Arduino Ethernet Shield 2 + * by Arduino.org team + * + */ + + +#ifndef ethernetudp_h +#define ethernetudp_h + +#include + +#define UDP_TX_PACKET_MAX_SIZE 24 + +class EthernetUDP : public UDP { +private: + uint8_t _sock; // socket ID for Wiz5100 + uint16_t _port; // local port to listen on + IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed + uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed + uint16_t _offset; // offset into the packet being sent + uint16_t _remaining; // remaining bytes of incoming packet yet to be processed + +public: + EthernetUDP(); // Constructor + virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + + //KH, to add Multicast support + virtual uint8_t beginMulticast(IPAddress, uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + ////// + + virtual void stop(); // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket(); + // Write a single byte into the packet + virtual size_t write(uint8_t); + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket(); + // Number of bytes remaining in the current packet + virtual int available(); + // Read a single byte from the current packet + virtual int read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(); + virtual void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() { return _remoteIP; }; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() { return _remotePort; }; +}; + +#endif diff --git a/LibraryPatches/Ethernet3/src/Ethernet3.cpp b/LibraryPatches/Ethernet3/src/Ethernet3.cpp new file mode 100644 index 0000000..23ad359 --- /dev/null +++ b/LibraryPatches/Ethernet3/src/Ethernet3.cpp @@ -0,0 +1,443 @@ +/* + modified 12 Aug 2013 + by Soohwan Kim (suhwan@wiznet.co.kr) + +- 10 Apr. 2015 + Added support for Arduino Ethernet Shield 2 + by Arduino.org team + + */ + +#include "Ethernet3.h" +#include "Dhcp.h" + +// XXX: don't make assumptions about the value of MAX_SOCK_NUM. +uint8_t EthernetClass::_state[MAX_SOCK_NUM] = { 0, }; +uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = { 0, }; + +void EthernetClass::setRstPin(uint8_t pinRST) { + _pinRST = pinRST; + pinMode(_pinRST, OUTPUT); + digitalWrite(_pinRST, HIGH); + } +void EthernetClass::setCsPin(uint8_t pinCS) { + _pinCS = pinCS; + } + +void EthernetClass::init(uint8_t maxSockNum) { + _maxSockNum = maxSockNum; + } + +uint8_t EthernetClass::softreset() { + return w5500.softReset(); + } + +void EthernetClass::hardreset() { + if(_pinRST != 0) { + digitalWrite(_pinRST, LOW); + delay(1); + digitalWrite(_pinRST, HIGH); + delay(150); + } + } + +#if defined(WIZ550io_WITH_MACADDRESS) + +int EthernetClass::begin(void) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var _mac_address + //uint8_t mac_address[6] ={0,}; + ////// + + _dhcp = new DhcpClass(); + + // Initialise the basic info + w5500.init(_maxSockNum, _pinCS); + w5500.setIPAddress(IPAddress(0,0,0,0).raw_address()); + + // KH mod + w5500.getMACAddress(_mac_address); + ////// + + if (strlen(_customHostname) != 0) + { + _dhcp->setCustomHostname(_customHostname); + } + + // Now try to get our config info from a DHCP server + // KH mod + int ret = _dhcp->beginWithDHCP(_mac_address); + ////// + + if(ret == 1) + { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + w5500.setIPAddress(_dhcp->getLocalIp().raw_address()); + w5500.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + w5500.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + _dnsServerAddress = _dhcp->getDnsServerIp(); + } + return ret; +} + +void EthernetClass::begin(IPAddress local_ip) +{ + IPAddress subnet(255, 255, 255, 0); + begin(local_ip, subnet); +} + +void EthernetClass::begin(IPAddress local_ip, IPAddress subnet) +{ + // Assume the gateway will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress gateway = local_ip; + gateway[3] = 1; + begin(local_ip, subnet, gateway); +} + +void EthernetClass::begin(IPAddress local_ip, IPAddress subnet, IPAddress gateway) +{ + // Assume the DNS server will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress dns_server = local_ip; + dns_server[3] = 1; + begin(local_ip, subnet, gateway, dns_server); +} + +void EthernetClass::begin(IPAddress local_ip, IPAddress subnet, IPAddress gateway, IPAddress dns_server) +{ + w5500.init(_maxSockNum, _pinCS); + w5500.setIPAddress(local_ip.raw_address()); + w5500.setGatewayIp(gateway.raw_address()); + w5500.setSubnetMask(subnet.raw_address()); + _dnsServerAddress = dns_server; +} + +#else +int EthernetClass::begin(uint8_t *mac_address) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac_address, sizeof(_mac_address)); + ////// + + _dhcp = new DhcpClass(); + // Initialise the basic info + w5500.init(_maxSockNum, _pinCS); + w5500.setMACAddress(mac_address); + w5500.setIPAddress(IPAddress(0,0,0,0).raw_address()); + + if (strlen(_customHostname) != 0) + { + _dhcp->setCustomHostname(_customHostname); + } + + // Now try to get our config info from a DHCP server + int ret = _dhcp->beginWithDHCP(mac_address); + if(ret == 1) + { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + w5500.setIPAddress(_dhcp->getLocalIp().raw_address()); + w5500.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + w5500.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + _dnsServerAddress = _dhcp->getDnsServerIp(); + } + + return ret; +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac_address, sizeof(_mac_address)); + ////// + + IPAddress subnet(255, 255, 255, 0); + begin(mac_address, local_ip, subnet); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress subnet) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac_address, sizeof(_mac_address)); + ////// + + // Assume the gateway will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress gateway = local_ip; + gateway[3] = 1; + begin(mac_address, local_ip, subnet, gateway); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress subnet, IPAddress gateway) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac_address, sizeof(_mac_address)); + ////// + + // Assume the DNS server will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress dns_server = local_ip; + dns_server[3] = 1; + begin(mac_address, local_ip, subnet, gateway, dns_server); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress subnet, IPAddress gateway, IPAddress dns_server) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac_address, sizeof(_mac_address)); + ////// + + w5500.init(_maxSockNum, _pinCS); + w5500.setMACAddress(mac_address); + w5500.setIPAddress(local_ip.raw_address()); + w5500.setGatewayIp(gateway.raw_address()); + w5500.setSubnetMask(subnet.raw_address()); + _dnsServerAddress = dns_server; +} + +#endif + +int EthernetClass::maintain(){ + int rc = DHCP_CHECK_NONE; + if(_dhcp != NULL){ + //we have a pointer to dhcp, use it + rc = _dhcp->checkLease(); + switch ( rc ){ + case DHCP_CHECK_NONE: + //nothing done + break; + case DHCP_CHECK_RENEW_OK: + case DHCP_CHECK_REBIND_OK: + //we might have got a new IP. + w5500.setIPAddress(_dhcp->getLocalIp().raw_address()); + w5500.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + w5500.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + _dnsServerAddress = _dhcp->getDnsServerIp(); + break; + default: + //this is actually a error, it will retry though + break; + } + } + return rc; +} + +void EthernetClass::WoL(bool wol) { + uint8_t val = w5500.readMR(); + bitWrite(val, 5, wol); + w5500.writeMR(val); + } + +bool EthernetClass::WoL() { + uint8_t val = w5500.readMR(); + return bitRead(val, 5); + } + +void EthernetClass::phyMode(phyMode_t mode) { + uint8_t val = w5500.getPHYCFGR(); + bitWrite(val, 6, 1); + if (mode == HALF_DUPLEX_10) { + bitWrite(val, 3, 0); + bitWrite(val, 4, 0); + bitWrite(val, 5, 0); + w5500.setPHYCFGR(val); + } + else if (mode == FULL_DUPLEX_10) { + bitWrite(val, 3, 1); + bitWrite(val, 4, 0); + bitWrite(val, 5, 0); + w5500.setPHYCFGR(val); + } + else if (mode == HALF_DUPLEX_100) { + bitWrite(val, 3, 0); + bitWrite(val, 4, 1); + bitWrite(val, 5, 0); + w5500.setPHYCFGR(val); + } + else if (mode == FULL_DUPLEX_100) { + bitWrite(val, 3, 1); + bitWrite(val, 4, 1); + bitWrite(val, 5, 0); + w5500.setPHYCFGR(val); + } + else if (mode == FULL_DUPLEX_100_AUTONEG) { + bitWrite(val, 3, 0); + bitWrite(val, 4, 0); + bitWrite(val, 5, 1); + w5500.setPHYCFGR(val); + } + else if (mode == POWER_DOWN) { + bitWrite(val, 3, 0); + bitWrite(val, 4, 1); + bitWrite(val, 5, 1); + w5500.setPHYCFGR(val); + } + else if (mode == ALL_AUTONEG) { + bitWrite(val, 3, 1); + bitWrite(val, 4, 1); + bitWrite(val, 5, 1); + w5500.setPHYCFGR(val); + } + bitWrite(val, 7, 0); + w5500.setPHYCFGR(val); + bitWrite(val, 7, 1); + w5500.setPHYCFGR(val); + } + +void EthernetClass::setHostname(char* hostname) { + memset(_customHostname, 0, 32); + memcpy((void*)_customHostname, (void*)hostname, strlen(hostname) >= 31 ? 31 : strlen(hostname)); + } + +uint8_t EthernetClass::phyState() { + return w5500.getPHYCFGR(); + } + +uint8_t EthernetClass::link() { + return bitRead(w5500.getPHYCFGR(), 0); + } + +const char* EthernetClass::linkReport() +{ + if (bitRead(w5500.getPHYCFGR(), 0) == 1) + return "LINK"; + else + return "NO LINK"; + } + +uint8_t EthernetClass::speed() +{ + if (bitRead(w5500.getPHYCFGR(), 0) == 1) + { + if (bitRead(w5500.getPHYCFGR(), 1) == 1) + return 100; + + if (bitRead(w5500.getPHYCFGR(), 1) == 0) + return 10; + + // KH add to fix compile error in some boards + return 0; + } + else + return 0; +} + +const char* EthernetClass::speedReport() +{ + if (bitRead(w5500.getPHYCFGR(), 0) == 1) + { + if (bitRead(w5500.getPHYCFGR(), 1) == 1) + return "100 MB"; + + if (bitRead(w5500.getPHYCFGR(), 1) == 0) + return "10 MB"; + + // KH add to fix compile error in some boards + return "NO LINK"; + } + else + return "NO LINK"; +} + +uint8_t EthernetClass::duplex() +{ + if(bitRead(w5500.getPHYCFGR(), 0) == 1) + { + if (bitRead(w5500.getPHYCFGR(), 2) == 1) + return 2; + + if (bitRead(w5500.getPHYCFGR(), 2) == 0) + return 1; + + // KH add to fix compile error in some boards + return 0; + } + else + return 0; +} + +const char* EthernetClass::duplexReport() +{ + if (bitRead(w5500.getPHYCFGR(), 0) == 1) + { + if(bitRead(w5500.getPHYCFGR(), 2) == 1) + return "FULL DUPLEX"; + + if (bitRead(w5500.getPHYCFGR(), 2) == 0) + return "HALF DUPLEX"; + + // KH add to fix compile error in some boards + return "NO LINK"; + } + else + return "NO LINK"; +} + +void EthernetClass::setRtTimeOut(uint16_t timeout) { + w5500.setRetransmissionTime(timeout); + } + +uint16_t EthernetClass::getRtTimeOut() { + return w5500.getRetransmissionTime(); + } + +void EthernetClass::setRtCount(uint8_t count) { + w5500.setRetransmissionCount(count); + } + +uint8_t EthernetClass::getRtCount() { + return w5500.getRetransmissionCount(); + } + +void EthernetClass::macAddress(uint8_t mac[]) { + w5500.getMACAddress(mac); + } + +const char* EthernetClass::macAddressReport() { + uint8_t mac[6]; + static char str[18]; + w5500.getMACAddress(mac); + sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return str; + } + +IPAddress EthernetClass::localIP() +{ + IPAddress ret; + w5500.getIPAddress(ret.raw_address()); + return ret; +} + +IPAddress EthernetClass::subnetMask() +{ + IPAddress ret; + w5500.getSubnetMask(ret.raw_address()); + return ret; +} + +IPAddress EthernetClass::gatewayIP() +{ + IPAddress ret; + w5500.getGatewayIp(ret.raw_address()); + return ret; +} + +IPAddress EthernetClass::dnsServerIP() +{ + return _dnsServerAddress; +} + +EthernetClass Ethernet; diff --git a/LibraryPatches/Ethernet3/src/Ethernet3.h b/LibraryPatches/Ethernet3/src/Ethernet3.h new file mode 100644 index 0000000..afa7db4 --- /dev/null +++ b/LibraryPatches/Ethernet3/src/Ethernet3.h @@ -0,0 +1,127 @@ +/* + modified 12 Aug 2013 + by Soohwan Kim (suhwan@wiznet.co.kr) + + - 10 Apr. 2015 + Added support for Arduino Ethernet Shield 2 + by Arduino.org team + + */ +#ifndef ethernet3_h +#define ethernet3_h + +#include +#include "utility/w5500.h" +#include "IPAddress.h" +#include "EthernetClient.h" +#include "EthernetServer.h" +#include "Dhcp.h" + +enum phyMode_t { + HALF_DUPLEX_10, + FULL_DUPLEX_10, + HALF_DUPLEX_100, + FULL_DUPLEX_100, + FULL_DUPLEX_100_AUTONEG, + POWER_DOWN, + ALL_AUTONEG + }; + +class EthernetClass { +private: + IPAddress _dnsServerAddress; + DhcpClass* _dhcp; + char _customHostname[32]; + + // KH add to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + uint8_t _mac_address[6] ={0,}; + ////// + +public: + uint8_t _maxSockNum; + uint8_t _pinCS; + uint8_t _pinRST; + + static uint8_t _state[MAX_SOCK_NUM]; + static uint16_t _server_port[MAX_SOCK_NUM]; + + EthernetClass() { _dhcp = NULL; _pinCS = 10; _maxSockNum = 8; } + + void setRstPin(uint8_t pinRST = 9); // for WIZ550io or USR-ES1, must set befor Ethernet.begin + void setCsPin(uint8_t pinCS = 10); // must set befor Ethernet.begin + + // Initialize with less sockets but more RX/TX Buffer + // maxSockNum = 1 Socket 0 -> RX/TX Buffer 16k + // maxSockNum = 2 Socket 0, 1 -> RX/TX Buffer 8k + // maxSockNum = 4 Socket 0...3 -> RX/TX Buffer 4k + // maxSockNum = 8 (Standard) all sockets -> RX/TX Buffer 2k + // be carefull of the MAX_SOCK_NUM, because in the moment it can't dynamicly changed + void init(uint8_t maxSockNum = 8); + + uint8_t softreset(); // can set only after Ethernet.begin + void hardreset(); // You need to set the Rst pin + +#if defined(WIZ550io_WITH_MACADDRESS) + + // Initialize function when use the ioShield serise (included WIZ550io) + // WIZ550io has a MAC address which is written after reset. + // Default IP, Gateway and subnet address are also writen. + // so, It needs some initial time. please refer WIZ550io Datasheet in details. + int begin(void); + void begin(IPAddress local_ip); + void begin(IPAddress local_ip, IPAddress subnet); + void begin(IPAddress local_ip, IPAddress subnet, IPAddress gateway); + void begin(IPAddress local_ip, IPAddress subnet, IPAddress gateway, IPAddress dns_server); +#else + // Initialize the Ethernet shield to use the provided MAC address and gain the rest of the + // configuration through DHCP. + // Returns 0 if the DHCP configuration failed, and 1 if it succeeded + int begin(uint8_t *mac_address); + void begin(uint8_t *mac_address, IPAddress local_ip); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress subnet); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress subnet, IPAddress gateway); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress subnet, IPAddress gateway, IPAddress dns_server); +#endif + + int maintain(); + void WoL(bool wol); // set Wake on LAN + bool WoL(); // get the WoL state + void phyMode(phyMode_t mode); // set PHYCFGR + uint8_t phyState(); // returns the PHYCFGR + uint8_t link(); // returns the linkstate, 1 = linked, 0 = no link + const char* linkReport(); // returns the linkstate as a string + uint8_t speed(); // returns speed in MB/s + const char* speedReport(); // returns speed as a string + uint8_t duplex(); // returns duplex mode 0 = no link, 1 = Half Duplex, 2 = Full Duplex + const char* duplexReport(); // returns duplex mode as a string + + void setRtTimeOut(uint16_t timeout = 2000); // set the retransmission timout *100us + uint16_t getRtTimeOut(); // get the retransmission timout + void setRtCount(uint8_t count = 8); // set the retransmission count + uint8_t getRtCount(); // get the retransmission count + + void macAddress(uint8_t mac[]); // get the MAC Address + const char* macAddressReport(); // returns the the MAC Address as a string + + void setHostname(char* hostname); + + // KH add to have similar function to Ethernet lib + // Certainly we can use void macAddress(uint8_t mac[]) to read from W5x00. + void MACAddress(uint8_t *mac_address) + { + memcpy(mac_address, _mac_address, sizeof(_mac_address)); + } + ////// + + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP(); + + friend class EthernetClient; + friend class EthernetServer; +}; + +extern EthernetClass Ethernet; + +#endif diff --git a/LibraryPatches/EthernetLarge/src/EthernetLarge.cpp b/LibraryPatches/EthernetLarge/src/EthernetLarge.cpp new file mode 100644 index 0000000..4357b3c --- /dev/null +++ b/LibraryPatches/EthernetLarge/src/EthernetLarge.cpp @@ -0,0 +1,318 @@ +/**************************************************************************************************************************** + EthernetLarge.cpp + + EthernetWebServer is a library for the Ethernet shields to run WebServer + + Based on and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Built by Khoi Hoang https://github.com/khoih-prog/EthernetWebServer + Licensed under MIT license + Version: 1.0.9 + + Copyright 2018 Paul Stoffregen + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2020 Initial coding for Arduino Mega, Teensy, etc to support Ethernetx libraries + 1.0.1 K Hoang 20/02/2020 Add support to lambda functions + 1.0.2 K Hoang 20/02/2020 Add support to UIPEthernet library for ENC28J60 + 1.0.3 K Hoang 23/02/2020 Add support to SAM DUE / SAMD21 boards + 1.0.4 K Hoang 16/04/2020 Add support to SAMD51 boards + 1.0.5 K Hoang 24/04/2020 Add support to nRF52 boards, such as AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, + Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B30_ublox, etc. + More Custom Ethernet libraries supported such as Ethernet2, Ethernet3, EthernetLarge + 1.0.6 K Hoang 27/04/2020 Add support to ESP32/ESP8266 boards + 1.0.7 K Hoang 30/04/2020 Add ENC28J60 support to ESP32/ESP8266 boards + 1.0.8 K Hoang 12/05/2020 Fix W5x00 support for ESP8266 boards. + 1.0.9 K Hoang 15/05/2020 Add EthernetWrapper.h for easier W5x00 support as well as more Ethernet libs in the future. + *****************************************************************************************************************************/ + +#include +#include "EthernetLarge.h" +#include "utility/w5100.h" +#include "Dhcp.h" + +#define ETHERNET_DEBUG 1 + +IPAddress EthernetClass::_dnsServerAddress; +DhcpClass* EthernetClass::_dhcp = NULL; + +// KH +void EthernetClass::setRstPin(uint8_t pinRST) +{ + _pinRST = pinRST; + pinMode(_pinRST, OUTPUT); + digitalWrite(_pinRST, HIGH); +} +void EthernetClass::setCsPin(uint8_t pinCS) +{ + _pinCS = pinCS; + W5100.setSS(pinCS); + +#if ( ETHERNET_DEBUG > 0 ) + Serial.print("Input pinCS = "); + Serial.println(pinCS); + Serial.print("_pinCS = "); + Serial.println(_pinCS); +#endif +} + +void EthernetClass::initMaxSockNum(uint8_t maxSockNum) +{ + _maxSockNum = maxSockNum; +} + +uint8_t EthernetClass::softreset() +{ + return W5100.softReset(); +} + +void EthernetClass::hardreset() +{ + if(_pinRST != 0) + { + digitalWrite(_pinRST, LOW); + delay(1); + digitalWrite(_pinRST, HIGH); + delay(150); + } +} + +int EthernetClass::begin(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) +{ + static DhcpClass s_dhcp; + _dhcp = &s_dhcp; + +#if ( ETHERNET_DEBUG > 0 ) + Serial.print("_pinCS = "); + Serial.print(_pinCS); +#endif + + // Initialise the basic info + if (W5100.init() == 0) + return 0; + + + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setMACAddress(mac); + W5100.setIPAddress(IPAddress(0,0,0,0).raw_address()); + SPI.endTransaction(); + + // Now try to get our config info from a DHCP server + int ret = _dhcp->beginWithDHCP(mac, timeout, responseTimeout); + if (ret == 1) { + // We've successfully found a DHCP server and got our configuration + // info, so set things accordingly + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); + W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + SPI.endTransaction(); + _dnsServerAddress = _dhcp->getDnsServerIp(); + socketPortRand(micros()); + } + return ret; +} + +void EthernetClass::begin(uint8_t *mac, IPAddress ip) +{ + // Assume the DNS server will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress dns = ip; + dns[3] = 1; + begin(mac, ip, dns); +} + +void EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns) +{ + // Assume the gateway will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress gateway = ip; + gateway[3] = 1; + begin(mac, ip, dns, gateway); +} + +void EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway) +{ + IPAddress subnet(255, 255, 255, 0); + begin(mac, ip, dns, gateway, subnet); +} + +void EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) +{ + // Initialise the basic info + if (W5100.init() == 0) + return; + + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setMACAddress(mac); +#if ( defined(ESP8266) || defined(ESP32) ) + W5100.setIPAddress(&ip[0]); + W5100.setGatewayIp(&gateway[0]); + W5100.setSubnetMask(&subnet[0]); +#elif ARDUINO > 106 || TEENSYDUINO > 121 + W5100.setIPAddress(ip._address.bytes); + W5100.setGatewayIp(gateway._address.bytes); + W5100.setSubnetMask(subnet._address.bytes); +#else + W5100.setIPAddress(ip._address); + W5100.setGatewayIp(gateway._address); + W5100.setSubnetMask(subnet._address); +#endif + SPI.endTransaction(); + _dnsServerAddress = dns; +} + +void EthernetClass::init(uint8_t sspin) +{ + W5100.setSS(sspin); +} + +EthernetLinkStatus EthernetClass::linkStatus() +{ + switch (W5100.getLinkStatus()) { + case UNKNOWN: return Unknown; + case LINK_ON: return LinkON; + case LINK_OFF: return LinkOFF; + default: return Unknown; + } +} + +EthernetHardwareStatus EthernetClass::hardwareStatus() +{ + switch (W5100.getChip()) { + case 51: return EthernetW5100; + case 52: return EthernetW5200; + case 55: return EthernetW5500; + default: return EthernetNoHardware; + } +} + +int EthernetClass::maintain() +{ + int rc = DHCP_CHECK_NONE; + if (_dhcp != NULL) { + // we have a pointer to dhcp, use it + rc = _dhcp->checkLease(); + switch (rc) + { + case DHCP_CHECK_NONE: + //nothing done + break; + case DHCP_CHECK_RENEW_OK: + case DHCP_CHECK_REBIND_OK: + //we might have got a new IP. + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); + W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + SPI.endTransaction(); + _dnsServerAddress = _dhcp->getDnsServerIp(); + break; + default: + //this is actually an error, it will retry though + break; + } + } + return rc; +} + + +void EthernetClass::MACAddress(uint8_t *mac_address) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getMACAddress(mac_address); + SPI.endTransaction(); +} + +IPAddress EthernetClass::localIP() +{ + IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getIPAddress(ret.raw_address()); + SPI.endTransaction(); + return ret; +} + +IPAddress EthernetClass::subnetMask() +{ + IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getSubnetMask(ret.raw_address()); + SPI.endTransaction(); + return ret; +} + +IPAddress EthernetClass::gatewayIP() +{ + IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getGatewayIp(ret.raw_address()); + SPI.endTransaction(); + return ret; +} + +void EthernetClass::setMACAddress(const uint8_t *mac_address) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setMACAddress(mac_address); + SPI.endTransaction(); +} + +void EthernetClass::setLocalIP(const IPAddress local_ip) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + IPAddress ip = local_ip; + W5100.setIPAddress(ip.raw_address()); + SPI.endTransaction(); +} + +void EthernetClass::setSubnetMask(const IPAddress subnet) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + IPAddress ip = subnet; + W5100.setSubnetMask(ip.raw_address()); + SPI.endTransaction(); +} + +void EthernetClass::setGatewayIP(const IPAddress gateway) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + IPAddress ip = gateway; + W5100.setGatewayIp(ip.raw_address()); + SPI.endTransaction(); +} + +void EthernetClass::setRetransmissionTimeout(uint16_t milliseconds) +{ + if (milliseconds > 6553) milliseconds = 6553; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setRetransmissionTime(milliseconds * 10); + SPI.endTransaction(); +} + +void EthernetClass::setRetransmissionCount(uint8_t num) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setRetransmissionCount(num); + SPI.endTransaction(); +} + + +EthernetClass Ethernet; diff --git a/LibraryPatches/EthernetLarge/src/EthernetLarge.h b/LibraryPatches/EthernetLarge/src/EthernetLarge.h new file mode 100644 index 0000000..4a18a2d --- /dev/null +++ b/LibraryPatches/EthernetLarge/src/EthernetLarge.h @@ -0,0 +1,362 @@ +/**************************************************************************************************************************** + EthernetLarge.h + + EthernetWebServer is a library for the Ethernet shields to run WebServer + + Based on and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Built by Khoi Hoang https://github.com/khoih-prog/EthernetWebServer + Licensed under MIT license + Version: 1.0.9 + + Copyright 2018 Paul Stoffregen + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2020 Initial coding for Arduino Mega, Teensy, etc to support Ethernetx libraries + 1.0.1 K Hoang 20/02/2020 Add support to lambda functions + 1.0.2 K Hoang 20/02/2020 Add support to UIPEthernet library for ENC28J60 + 1.0.3 K Hoang 23/02/2020 Add support to SAM DUE / SAMD21 boards + 1.0.4 K Hoang 16/04/2020 Add support to SAMD51 boards + 1.0.5 K Hoang 24/04/2020 Add support to nRF52 boards, such as AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, + Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B30_ublox, etc. + More Custom Ethernet libraries supported such as Ethernet2, Ethernet3, EthernetLarge + 1.0.6 K Hoang 27/04/2020 Add support to ESP32/ESP8266 boards + 1.0.7 K Hoang 30/04/2020 Add ENC28J60 support to ESP32/ESP8266 boards + 1.0.8 K Hoang 12/05/2020 Fix W5x00 support for ESP8266 boards. + 1.0.9 K Hoang 15/05/2020 Add EthernetWrapper.h for easier W5x00 support as well as more Ethernet libs in the future. + *****************************************************************************************************************************/ + +#ifndef ethernet_h_ +#define ethernet_h_ + +// All symbols exposed to Arduino sketches are contained in this header file +// +// Older versions had much of this stuff in EthernetClient.h, EthernetServer.h, +// and socket.h. Including headers in different order could cause trouble, so +// these "friend" classes are now defined in the same header file. socket.h +// was removed to avoid possible conflict with the C library header files. + + +// Configure the maximum number of sockets to support. W5100 chips can have +// up to 4 sockets. W5200 & W5500 can have up to 8 sockets. Several bytes +// of RAM are used for each socket. Reducing the maximum can save RAM, but +// you are limited to fewer simultaneous connections. +#define MAX_SOCK_NUM 2 + +// By default, each socket uses 2K buffers inside the Wiznet chip. If +// MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting +// this will use larger buffers within the Wiznet chip. Large buffers +// can really help with UDP protocols like Artnet. In theory larger +// buffers should allow faster TCP over high-latency links, but this +// does not always seem to work in practice (maybe Wiznet bugs?) +#define ETHERNET_LARGE_BUFFERS + + +#include +#include "Client.h" +#include "Server.h" +#include "Udp.h" + +enum EthernetLinkStatus { + Unknown, + LinkON, + LinkOFF +}; + +enum EthernetHardwareStatus { + EthernetNoHardware, + EthernetW5100, + EthernetW5200, + EthernetW5500 +}; + +class EthernetUDP; +class EthernetClient; +class EthernetServer; +class DhcpClass; + +class EthernetClass { +private: + static IPAddress _dnsServerAddress; + static DhcpClass* _dhcp; +public: + // KH + uint8_t _maxSockNum; + uint8_t _pinCS; + uint8_t _pinRST; + + void setRstPin(uint8_t pinRST = 9); // for WIZ550io or USR-ES1, must set befor Ethernet.begin + void setCsPin(uint8_t pinCS = 10); // must set befor Ethernet.begin + + // Initialize with less sockets but more RX/TX Buffer + // maxSockNum = 1 Socket 0 -> RX/TX Buffer 16k + // maxSockNum = 2 Socket 0, 1 -> RX/TX Buffer 8k + // maxSockNum = 4 Socket 0...3 -> RX/TX Buffer 4k + // maxSockNum = 8 (Standard) all sockets -> RX/TX Buffer 2k + // be carefull of the MAX_SOCK_NUM, because in the moment it can't dynamicly changed + void initMaxSockNum(uint8_t maxSockNum = 8); + + uint8_t softreset(); // can set only after Ethernet.begin + void hardreset(); // You need to set the Rst pin + + // Initialise the Ethernet shield to use the provided MAC address and + // gain the rest of the configuration through DHCP. + // Returns 0 if the DHCP configuration failed, and 1 if it succeeded + int begin(uint8_t *mac, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int maintain(); + EthernetLinkStatus linkStatus(); + EthernetHardwareStatus hardwareStatus(); + + // Manual configuration + void begin(uint8_t *mac, IPAddress ip); + void begin(uint8_t *mac, IPAddress ip, IPAddress dns); + void begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway); + void begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); + void init(uint8_t sspin = 10); + + void MACAddress(uint8_t *mac_address); + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP() { return _dnsServerAddress; } + + void setMACAddress(const uint8_t *mac_address); + void setLocalIP(const IPAddress local_ip); + void setSubnetMask(const IPAddress subnet); + void setGatewayIP(const IPAddress gateway); + void setDnsServerIP(const IPAddress dns_server) { _dnsServerAddress = dns_server; } + void setRetransmissionTimeout(uint16_t milliseconds); + void setRetransmissionCount(uint8_t num); + + friend class EthernetClient; + friend class EthernetServer; + friend class EthernetUDP; +private: + // Opens a socket(TCP or UDP or IP_RAW mode) + uint8_t socketBegin(uint8_t protocol, uint16_t port); + uint8_t socketBeginMulticast(uint8_t protocol, IPAddress ip,uint16_t port); + uint8_t socketStatus(uint8_t s); + // Close socket + void socketClose(uint8_t s); + // Establish TCP connection (Active connection) + void socketConnect(uint8_t s, uint8_t * addr, uint16_t port); + // disconnect the connection + void socketDisconnect(uint8_t s); + // Establish TCP connection (Passive connection) + uint8_t socketListen(uint8_t s); + // Send data (TCP) + uint16_t socketSend(uint8_t s, const uint8_t * buf, uint16_t len); + uint16_t socketSendAvailable(uint8_t s); + // Receive data (TCP) + int socketRecv(uint8_t s, uint8_t * buf, int16_t len); + uint16_t socketRecvAvailable(uint8_t s); + uint8_t socketPeek(uint8_t s); + // sets up a UDP datagram, the data for which will be provided by one + // or more calls to bufferData and then finally sent with sendUDP. + // return true if the datagram was successfully set up, or false if there was an error + bool socketStartUDP(uint8_t s, uint8_t* addr, uint16_t port); + // copy up to len bytes of data from buf into a UDP datagram to be + // sent later by sendUDP. Allows datagrams to be built up from a series of bufferData calls. + // return Number of bytes successfully buffered + uint16_t socketBufferData(uint8_t s, uint16_t offset, const uint8_t* buf, uint16_t len); + // Send a UDP datagram built up from a sequence of startUDP followed by one or more + // calls to bufferData. + // return true if the datagram was successfully sent, or false if there was an error + bool socketSendUDP(uint8_t s); + // Initialize the "random" source port number + void socketPortRand(uint16_t n); +}; + +extern EthernetClass Ethernet; + + +#define UDP_TX_PACKET_MAX_SIZE 24 + +class EthernetUDP : public UDP { +private: + uint16_t _port; // local port to listen on + IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed + uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed + uint16_t _offset; // offset into the packet being sent + +protected: + uint8_t sockindex; + uint16_t _remaining; // remaining bytes of incoming packet yet to be processed + +public: + EthernetUDP() : sockindex(MAX_SOCK_NUM) {} // Constructor + virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t beginMulticast(IPAddress, uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop(); // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket(); + // Write a single byte into the packet + virtual size_t write(uint8_t); + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket(); + // Number of bytes remaining in the current packet + virtual int available(); + // Read a single byte from the current packet + virtual int read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(); + virtual void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() { return _remoteIP; }; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() { return _remotePort; }; + virtual uint16_t localPort() { return _port; } +}; + + + + +class EthernetClient : public Client { +public: + EthernetClient() : sockindex(MAX_SOCK_NUM), _timeout(1000) { } + EthernetClient(uint8_t s) : sockindex(s), _timeout(1000) { } + + uint8_t status(); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual int availableForWrite(void); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool() { return sockindex < MAX_SOCK_NUM; } + virtual bool operator==(const bool value) { return bool() == value; } + virtual bool operator!=(const bool value) { return bool() != value; } + virtual bool operator==(const EthernetClient&); + virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); } + uint8_t getSocketNumber() const { return sockindex; } + virtual uint16_t localPort(); + virtual IPAddress remoteIP(); + virtual uint16_t remotePort(); + virtual void setConnectionTimeout(uint16_t timeout) { _timeout = timeout; } + + friend class EthernetServer; + + using Print::write; + +private: + uint8_t sockindex; // MAX_SOCK_NUM means client not in use + uint16_t _timeout; +}; + + +class EthernetServer : public Server { +private: + uint16_t _port; +public: + EthernetServer(uint16_t port) : _port(port) { } + EthernetClient available(); + EthernetClient accept(); + virtual void begin(); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual operator bool(); + using Print::write; + //void statusreport(); + + // TODO: make private when socket allocation moves to EthernetClass + static uint16_t server_port[MAX_SOCK_NUM]; +}; + + +class DhcpClass { +private: + uint32_t _dhcpInitialTransactionId; + uint32_t _dhcpTransactionId; + uint8_t _dhcpMacAddr[6]; +#ifdef __arm__ + uint8_t _dhcpLocalIp[4] __attribute__((aligned(4))); + uint8_t _dhcpSubnetMask[4] __attribute__((aligned(4))); + uint8_t _dhcpGatewayIp[4] __attribute__((aligned(4))); + uint8_t _dhcpDhcpServerIp[4] __attribute__((aligned(4))); + uint8_t _dhcpDnsServerIp[4] __attribute__((aligned(4))); +#else + uint8_t _dhcpLocalIp[4]; + uint8_t _dhcpSubnetMask[4]; + uint8_t _dhcpGatewayIp[4]; + uint8_t _dhcpDhcpServerIp[4]; + uint8_t _dhcpDnsServerIp[4]; +#endif + uint32_t _dhcpLeaseTime; + uint32_t _dhcpT1, _dhcpT2; + uint32_t _renewInSec; + uint32_t _rebindInSec; + unsigned long _timeout; + unsigned long _responseTimeout; + unsigned long _lastCheckLeaseMillis; + uint8_t _dhcp_state; + EthernetUDP _dhcpUdpSocket; + + int request_DHCP_lease(); + void reset_DHCP_lease(); + void presend_DHCP(); + void send_DHCP_MESSAGE(uint8_t, uint16_t); + void printByte(char *, uint8_t); + + uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId); +public: + IPAddress getLocalIp(); + IPAddress getSubnetMask(); + IPAddress getGatewayIp(); + IPAddress getDhcpServerIp(); + IPAddress getDnsServerIp(); + + int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int checkLease(); +}; + + + + + +#endif diff --git a/LibraryPatches/EthernetLarge/src/EthernetServer.cpp b/LibraryPatches/EthernetLarge/src/EthernetServer.cpp new file mode 100644 index 0000000..a77b569 --- /dev/null +++ b/LibraryPatches/EthernetLarge/src/EthernetServer.cpp @@ -0,0 +1,240 @@ +/**************************************************************************************************************************** + EthernetServer.cpp + + EthernetWebServer is a library for the Ethernet shields to run WebServer + + Based on and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Built by Khoi Hoang https://github.com/khoih-prog/EthernetWebServer + Licensed under MIT license + Version: 1.0.9 + + Copyright 2018 Paul Stoffregen + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2020 Initial coding for Arduino Mega, Teensy, etc to support Ethernetx libraries + 1.0.1 K Hoang 20/02/2020 Add support to lambda functions + 1.0.2 K Hoang 20/02/2020 Add support to UIPEthernet library for ENC28J60 + 1.0.3 K Hoang 23/02/2020 Add support to SAM DUE / SAMD21 boards + 1.0.4 K Hoang 16/04/2020 Add support to SAMD51 boards + 1.0.5 K Hoang 24/04/2020 Add support to nRF52 boards, such as AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, + Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B30_ublox, etc. + More Custom Ethernet libraries supported such as Ethernet2, Ethernet3, EthernetLarge + 1.0.6 K Hoang 27/04/2020 Add support to ESP32/ESP8266 boards + 1.0.7 K Hoang 30/04/2020 Add ENC28J60 support to ESP32/ESP8266 boards + 1.0.8 K Hoang 12/05/2020 Fix W5x00 support for ESP8266 boards. + 1.0.9 K Hoang 15/05/2020 Add EthernetWrapper.h for easier W5x00 support as well as more Ethernet libs in the future. + *****************************************************************************************************************************/ + +#include +#include "EthernetLarge.h" +#include "utility/w5100.h" + +uint16_t EthernetServer::server_port[MAX_SOCK_NUM]; + + +void EthernetServer::begin() +{ + uint8_t sockindex = Ethernet.socketBegin(SnMR::TCP, _port); + if (sockindex < MAX_SOCK_NUM) { + if (Ethernet.socketListen(sockindex)) { + server_port[sockindex] = _port; + } else { + Ethernet.socketDisconnect(sockindex); + } + } +} + +EthernetClient EthernetServer::available() +{ + bool listening = false; + uint8_t sockindex = MAX_SOCK_NUM; + uint8_t chip, maxindex=MAX_SOCK_NUM; + + chip = W5100.getChip(); + if (!chip) return EthernetClient(MAX_SOCK_NUM); +#if MAX_SOCK_NUM > 4 + if (chip == 51) maxindex = 4; // W5100 chip never supports more than 4 sockets +#endif + + for (uint8_t i=0; i < maxindex; i++) + { + if (server_port[i] == _port) + { + uint8_t stat = Ethernet.socketStatus(i); + if (stat == SnSR::ESTABLISHED || stat == SnSR::CLOSE_WAIT) + { + if (Ethernet.socketRecvAvailable(i) > 0) + { + sockindex = i; + } + else + { + // remote host closed connection, our end still open + if (stat == SnSR::CLOSE_WAIT) + { + Ethernet.socketDisconnect(i); + // status becomes LAST_ACK for short time + } + } + } + else if (stat == SnSR::LISTEN) + { + listening = true; + } + else if (stat == SnSR::CLOSED) + { + server_port[i] = 0; + } + } + } + + if (!listening) + { + begin(); + } + + return EthernetClient(sockindex); +} + +EthernetClient EthernetServer::accept() +{ + bool listening = false; + uint8_t sockindex = MAX_SOCK_NUM; + uint8_t chip, maxindex=MAX_SOCK_NUM; + + chip = W5100.getChip(); + if (!chip) return EthernetClient(MAX_SOCK_NUM); +#if MAX_SOCK_NUM > 4 + if (chip == 51) maxindex = 4; // W5100 chip never supports more than 4 sockets +#endif + + for (uint8_t i=0; i < maxindex; i++) + { + if (server_port[i] == _port) + { + uint8_t stat = Ethernet.socketStatus(i); + + if (sockindex == MAX_SOCK_NUM && (stat == SnSR::ESTABLISHED || stat == SnSR::CLOSE_WAIT)) + { + // Return the connected client even if no data received. + // Some protocols like FTP expect the server to send the + // first data. + sockindex = i; + server_port[i] = 0; // only return the client once + } + else if (stat == SnSR::LISTEN) + { + listening = true; + } + else if (stat == SnSR::CLOSED) + { + server_port[i] = 0; + } + } + } + + if (!listening) + begin(); + + return EthernetClient(sockindex); +} + +EthernetServer::operator bool() +{ + uint8_t maxindex=MAX_SOCK_NUM; +#if MAX_SOCK_NUM > 4 + if (W5100.getChip() == 51) maxindex = 4; // W5100 chip never supports more than 4 sockets +#endif + + for (uint8_t i=0; i < maxindex; i++) + { + if (server_port[i] == _port) + { + if (Ethernet.socketStatus(i) == SnSR::LISTEN) + { + return true; // server is listening for incoming clients + } + } + } + return false; +} + +#if 0 +void EthernetServer::statusreport() +{ + Serial.printf("EthernetServer, port=%d\n", _port); + for (uint8_t i=0; i < MAX_SOCK_NUM; i++) { + uint16_t port = server_port[i]; + uint8_t stat = Ethernet.socketStatus(i); + const char *name; + switch (stat) { + case 0x00: name = "CLOSED"; break; + case 0x13: name = "INIT"; break; + case 0x14: name = "LISTEN"; break; + case 0x15: name = "SYNSENT"; break; + case 0x16: name = "SYNRECV"; break; + case 0x17: name = "ESTABLISHED"; break; + case 0x18: name = "FIN_WAIT"; break; + case 0x1A: name = "CLOSING"; break; + case 0x1B: name = "TIME_WAIT"; break; + case 0x1C: name = "CLOSE_WAIT"; break; + case 0x1D: name = "LAST_ACK"; break; + case 0x22: name = "UDP"; break; + case 0x32: name = "IPRAW"; break; + case 0x42: name = "MACRAW"; break; + case 0x5F: name = "PPPOE"; break; + default: name = "???"; + } + int avail = Ethernet.socketRecvAvailable(i); + Serial.printf(" %d: port=%d, status=%s (0x%02X), avail=%d\n", + i, port, name, stat, avail); + } +} +#endif + +size_t EthernetServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t EthernetServer::write(const uint8_t *buffer, size_t size) +{ + uint8_t chip, maxindex=MAX_SOCK_NUM; + + chip = W5100.getChip(); + if (!chip) return 0; +#if MAX_SOCK_NUM > 4 + if (chip == 51) maxindex = 4; // W5100 chip never supports more than 4 sockets +#endif + available(); + + for (uint8_t i=0; i < maxindex; i++) + { + if (server_port[i] == _port) + { + if (Ethernet.socketStatus(i) == SnSR::ESTABLISHED) + { + Ethernet.socketSend(i, buffer, size); + } + } + } + return size; +} diff --git a/LibraryPatches/EthernetLarge/src/utility/w5100.cpp b/LibraryPatches/EthernetLarge/src/utility/w5100.cpp new file mode 100644 index 0000000..2e2e5a6 --- /dev/null +++ b/LibraryPatches/EthernetLarge/src/utility/w5100.cpp @@ -0,0 +1,703 @@ +/**************************************************************************************************************************** + w5100.cpp - Driver for W5x00 + + EthernetWebServer is a library for the Ethernet shields to run WebServer + + Based on and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Built by Khoi Hoang https://github.com/khoih-prog/EthernetWebServer + Licensed under MIT license + Version: 1.0.9 + + Copyright 2018 Paul Stoffregen + Copyright (c) 2010 by Cristian Maglie + + This file is free software; you can redistribute it and/or modify + it under the terms of either the GNU General Public License version 2 + or the GNU Lesser General Public License version 2.1, both as + published by the Free Software Foundation. + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2020 Initial coding for Arduino Mega, Teensy, etc to support Ethernetx libraries + 1.0.1 K Hoang 20/02/2020 Add support to lambda functions + 1.0.2 K Hoang 20/02/2020 Add support to UIPEthernet library for ENC28J60 + 1.0.3 K Hoang 23/02/2020 Add support to SAM DUE / SAMD21 boards + 1.0.4 K Hoang 16/04/2020 Add support to SAMD51 boards + 1.0.5 K Hoang 24/04/2020 Add support to nRF52 boards, such as AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, + Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B30_ublox, etc. + More Custom Ethernet libraries supported such as Ethernet2, Ethernet3, EthernetLarge + 1.0.6 K Hoang 27/04/2020 Add support to ESP32/ESP8266 boards + 1.0.7 K Hoang 30/04/2020 Add ENC28J60 support to ESP32/ESP8266 boards + 1.0.8 K Hoang 12/05/2020 Fix W5x00 support for ESP8266 boards. + 1.0.9 K Hoang 15/05/2020 Add EthernetWrapper.h for easier W5x00 support as well as more Ethernet libs in the future. + *****************************************************************************************************************************/ + +#include +#include "EthernetLarge.h" +#include "w5100.h" + +#define W5100_DEBUG 1 + +/***************************************************/ +/** Default SS pin setting **/ +/***************************************************/ + +// If variant.h or other headers specifically define the +// default SS pin for ethernet, use it. +#if defined(PIN_SPI_SS_ETHERNET_LIB) + +#define SS_PIN_DEFAULT PIN_SPI_SS_ETHERNET_LIB +//KH +#warning w5100.cpp Use PIN_SPI_SS_ETHERNET_LIB defined, change SS_PIN_DEFAULT to PIN_SPI_SS_ETHERNET_LIB + +// MKR boards default to pin 5 for MKR ETH +// Pins 8-10 are MOSI/SCK/MISO on MRK, so don't use pin 10 +#elif defined(USE_ARDUINO_MKR_PIN_LAYOUT) || defined(ARDUINO_SAMD_MKRZERO) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRFox1200) || defined(ARDUINO_SAMD_MKRGSM1400) || defined(ARDUINO_SAMD_MKRWAN1300) + +#define SS_PIN_DEFAULT 5 +//KH +#warning w5100.cpp Use MKR, change SS_PIN_DEFAULT to 5 + +// For boards using AVR, assume shields with SS on pin 10 +// will be used. This allows for Arduino Mega (where +// SS is pin 53) and Arduino Leonardo (where SS is pin 17) +// to work by default with Arduino Ethernet Shield R2 & R3. +#elif defined(__AVR__) + +#define SS_PIN_DEFAULT 10 +//KH +#warning w5100.cpp Use __AVR__, change SS_PIN_DEFAULT to 10 + +// If variant.h or other headers define these names +// use them if none of the other cases match +#elif defined(PIN_SPI_SS) + +#if defined(__SAMD21G18A__) +//10 - 2 (6 conflict) all not OK for Nano 33 IoT !!! SPI corrupted??? +#warning w5100.cpp Use __SAMD21G18A__, change SS_PIN_DEFAULT to 10 +#define SS_PIN_DEFAULT 10 +#else +#define SS_PIN_DEFAULT PIN_SPI_SS + +//KH +#warning w5100.cpp Use PIN_SPI_SS defined, change SS_PIN_DEFAULT to PIN_SPI_SS +#endif + +#elif defined(CORE_SS0_PIN) +#define SS_PIN_DEFAULT CORE_SS0_PIN + +//KH +#warning w5100.cpp Use CORE_SS0_PIN defined, change SS_PIN_DEFAULT to CORE_SS0_PIN + +//KH for ESP32 +#elif defined(ESP32) +//pin SS already defined in ESP32 as pin 5, don't use this as conflict with SPIFFS, EEPROM, etc. +// Use in GPIO22 +#warning w5100.cpp Use ESP32, change SS_PIN_DEFAULT to GPIO22, MOSI(23), MISO(19), SCK(18) +#define SS_PIN_DEFAULT 22 //SS +/////// + +//KH for ESP8266 +#elif defined(ESP8266) +//pin SS already defined in ESP8266 as pin 15. Conflict => Move to pin GPIO4 (D2) +#warning w5100.cpp Use ESP8266, change SS_PIN_DEFAULT to SS(4), MOSI(13), MISO(12), SCK(14) +#define SS_PIN_DEFAULT D2 // GPIO4, SS + +/////// + +// As a final fallback, use pin 10 +#else +#define SS_PIN_DEFAULT 10 + +//KH +#warning w5100.cpp Use fallback, change SS_PIN_DEFAULT to 10 + +#endif + +// W5100 controller instance +uint8_t W5100Class::chip = 0; +uint8_t W5100Class::CH_BASE_MSB; +uint8_t W5100Class::ss_pin = SS_PIN_DEFAULT; +#ifdef ETHERNET_LARGE_BUFFERS +uint16_t W5100Class::SSIZE = 2048; +uint16_t W5100Class::SMASK = 0x07FF; +#endif +W5100Class W5100; + +// pointers and bitmasks for optimized SS pin +#if defined(__AVR__) + volatile uint8_t * W5100Class::ss_pin_reg; + uint8_t W5100Class::ss_pin_mask; +#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__) + volatile uint8_t * W5100Class::ss_pin_reg; +#elif defined(__IMXRT1062__) + volatile uint32_t * W5100Class::ss_pin_reg; + uint32_t W5100Class::ss_pin_mask; +#elif defined(__MKL26Z64__) + volatile uint8_t * W5100Class::ss_pin_reg; + uint8_t W5100Class::ss_pin_mask; +#elif defined(__SAM3X8E__) || defined(__SAM3A8C__) || defined(__SAM3A4C__) + volatile uint32_t * W5100Class::ss_pin_reg; + uint32_t W5100Class::ss_pin_mask; +#elif defined(__PIC32MX__) + volatile uint32_t * W5100Class::ss_pin_reg; + uint32_t W5100Class::ss_pin_mask; +#elif defined(ARDUINO_ARCH_ESP8266) + volatile uint32_t * W5100Class::ss_pin_reg; + uint32_t W5100Class::ss_pin_mask; +#elif defined(__SAMD21G18A__) + volatile uint32_t * W5100Class::ss_pin_reg; + uint32_t W5100Class::ss_pin_mask; + #warning w5100.cpp Use __SAMD21G18A__ +#endif + +// KH +uint8_t W5100Class::init(uint8_t socketNumbers, uint8_t new_ss_pin) +{ + // KH + uint8_t i; + + if (initialized) return 1; + + // Many Ethernet shields have a CAT811 or similar reset chip + // connected to W5100 or W5200 chips. The W5200 will not work at + // all, and may even drive its MISO pin, until given an active low + // reset pulse! The CAT811 has a 240 ms typical pulse length, and + // a 400 ms worst case maximum pulse length. MAX811 has a worst + // case maximum 560 ms pulse length. This delay is meant to wait + // until the reset pulse is ended. If your hardware has a shorter + // reset time, this can be edited or removed. + delay(560); + + //W5100Class::ss_pin = new_ss_pin; + +#if ( W5100_DEBUG > 0 ) + //KH + Serial.print("\nW5100 init, using SS_PIN_DEFAULT = "); + Serial.print(SS_PIN_DEFAULT); + Serial.print(", new ss_pin = "); + Serial.print(new_ss_pin); + Serial.print(", W5100Class::ss_pin = "); + Serial.println(W5100Class::ss_pin); +#endif + + SPI.begin(); + + initSS(); + resetSS(); + + // From #define SPI_ETHERNET_SETTINGS SPISettings(14000000, MSBFIRST, SPI_MODE0) + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + + // Attempt W5200 detection first, because W5200 does not properly + // reset its SPI state when CS goes high (inactive). Communication + // from detecting the other chips can leave the W5200 in a state + // where it won't recover, unless given a reset pulse. + if (isW5200()) + { + CH_BASE_MSB = 0x40; +#ifdef ETHERNET_LARGE_BUFFERS +#if MAX_SOCK_NUM <= 1 + SSIZE = 16384; +#elif MAX_SOCK_NUM <= 2 + SSIZE = 8192; +#elif MAX_SOCK_NUM <= 4 + SSIZE = 4096; +#else + SSIZE = 2048; +#endif + SMASK = SSIZE - 1; +#endif + for (i=0; i> 10); + writeSnTX_SIZE(i, SSIZE >> 10); + } + for (; i<8; i++) + { + writeSnRX_SIZE(i, 0); + writeSnTX_SIZE(i, 0); + } + +#if ( W5100_DEBUG > 0 ) + Serial.print("W5100::init: W5200, SSIZE ="); + Serial.println(SSIZE); +#endif + + // Try W5500 next. Wiznet finally seems to have implemented + // SPI well with this chip. It appears to be very resilient, + // so try it after the fragile W5200 + } + else if (isW5500()) + { + CH_BASE_MSB = 0x10; +#ifdef ETHERNET_LARGE_BUFFERS +#if MAX_SOCK_NUM <= 1 + SSIZE = 16384; +#elif MAX_SOCK_NUM <= 2 + SSIZE = 8192; +#elif MAX_SOCK_NUM <= 4 + SSIZE = 4096; +#else + SSIZE = 2048; +#endif + SMASK = SSIZE - 1; + for (i=0; i> 10); + writeSnTX_SIZE(i, SSIZE >> 10); + } + for (; i<8; i++) + { + writeSnRX_SIZE(i, 0); + writeSnTX_SIZE(i, 0); + } +#endif + +#if ( W5100_DEBUG > 0 ) + Serial.print("W5100::init: W5500, SSIZE ="); + Serial.println(SSIZE); +#endif + + + // Try W5100 last. This simple chip uses fixed 4 byte frames + // for every 8 bit access. Terribly inefficient, but so simple + // it recovers from "hearing" unsuccessful W5100 or W5200 + // communication. W5100 is also the only chip without a VERSIONR + // register for identification, so we check this last. + } else if (isW5100()) + { + CH_BASE_MSB = 0x04; +#ifdef ETHERNET_LARGE_BUFFERS +#if MAX_SOCK_NUM <= 1 + SSIZE = 8192; + writeTMSR(0x03); + writeRMSR(0x03); +#elif MAX_SOCK_NUM <= 2 + SSIZE = 4096; + writeTMSR(0x0A); + writeRMSR(0x0A); +#else + SSIZE = 2048; + writeTMSR(0x55); + writeRMSR(0x55); +#endif + SMASK = SSIZE - 1; +#else + writeTMSR(0x55); + writeRMSR(0x55); +#endif + +#if ( W5100_DEBUG > 0 ) + Serial.print("W5100::init: W5100, SSIZE ="); + Serial.println(SSIZE); +#endif + + // No hardware seems to be present. Or it could be a W5200 + // that's heard other SPI communication if its chip select + // pin wasn't high when a SD card or other SPI chip was used. + } + else + { +#if ( W5100_DEBUG > 0 ) + Serial.println("no chip :-("); +#endif + + chip = 0; + SPI.endTransaction(); + return 0; // no known chip is responding :-( + } + SPI.endTransaction(); + initialized = true; + return 1; // successful init +} + +// Soft reset the Wiznet chip, by writing to its MR register reset bit +uint8_t W5100Class::softReset(void) +{ + uint16_t count=0; + +#if ( W5100_DEBUG > 1 ) + Serial.println("EthernetLarge:Wiznet soft reset"); +#endif + + // write to reset bit + writeMR(0x80); + // then wait for soft reset to complete + do + { + uint8_t mr = readMR(); + +#if ( W5100_DEBUG > 2 ) + Serial.print("mr="); + Serial.println(mr, HEX); +#endif + + if (mr == 0) + return 1; + + delay(1); + } while (++count < 20); + return 0; +} + + +uint8_t W5100Class::isW5100(void) +{ + chip = 51; + +#if ( W5100_DEBUG > 1 ) + Serial.println("W5100.cpp: detect W5100 chip"); +#endif + + if (!softReset()) + return 0; + + writeMR(0x10); + if (readMR() != 0x10) + return 0; + + writeMR(0x12); + if (readMR() != 0x12) + return 0; + + writeMR(0x00); + if (readMR() != 0x00) + return 0; + +#if ( W5100_DEBUG > 1 ) + Serial.println("chip is W5100"); +#endif + + return 1; +} + +uint8_t W5100Class::isW5200(void) +{ + chip = 52; + +#if ( W5100_DEBUG > 1 ) + Serial.println("W5100.cpp: detect W5200 chip"); +#endif + + if (!softReset()) + return 0; + + writeMR(0x08); + if (readMR() != 0x08) + return 0; + + writeMR(0x10); + if (readMR() != 0x10) + return 0; + + writeMR(0x00); + if (readMR() != 0x00) + return 0; + + int ver = readVERSIONR_W5200(); + +#if ( W5100_DEBUG > 1 ) + Serial.print("version="); + Serial.println(ver); +#endif + + if (ver != 3) + return 0; + +#if ( W5100_DEBUG > 1 ) + Serial.println("chip is W5200"); +#endif + + return 1; +} + +uint8_t W5100Class::isW5500(void) +{ + chip = 55; + +#if ( W5100_DEBUG > 1 ) + Serial.println("W5100.cpp: detect W5500 chip"); +#endif + + if (!softReset()) + return 0; + + writeMR(0x08); + if (readMR() != 0x08) + return 0; + + writeMR(0x10); + if (readMR() != 0x10) + return 0; + + writeMR(0x00); + if (readMR() != 0x00) + return 0; + + int ver = readVERSIONR_W5500(); + +#if ( W5100_DEBUG > 1 ) + Serial.print("version="); + Serial.println(ver); +#endif + + if (ver != 4) + return 0; + +#if ( W5100_DEBUG > 1 ) + Serial.println("chip is W5500"); +#endif + + return 1; +} + +W5100Linkstatus W5100Class::getLinkStatus() +{ + uint8_t phystatus; + + // KH + if (!initialized) return UNKNOWN; + + switch (chip) + { + case 52: + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + phystatus = readPSTATUS_W5200(); + SPI.endTransaction(); + if (phystatus & 0x20) + return LINK_ON; + + return LINK_OFF; + + case 55: + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + phystatus = readPHYCFGR_W5500(); + SPI.endTransaction(); + if (phystatus & 0x01) + return LINK_ON; + + return LINK_OFF; + + default: + return UNKNOWN; + } +} + +uint16_t W5100Class::write(uint16_t addr, const uint8_t *buf, uint16_t len) +{ + uint8_t cmd[8]; + + if (chip == 51) + { + for (uint16_t i=0; i> 8); + SPI.transfer(addr & 0xFF); + addr++; + SPI.transfer(buf[i]); + resetSS(); + } + } + else if (chip == 52) + { + setSS(); + cmd[0] = addr >> 8; + cmd[1] = addr & 0xFF; + cmd[2] = ((len >> 8) & 0x7F) | 0x80; + cmd[3] = len & 0xFF; + SPI.transfer(cmd, 4); + +#ifdef SPI_HAS_TRANSFER_BUF + SPI.transfer(buf, NULL, len); +#else + // TODO: copy 8 bytes at a time to cmd[] and block transfer + for (uint16_t i=0; i < len; i++) + { + SPI.transfer(buf[i]); + } +#endif + resetSS(); + } + else + { + // chip == 55 + setSS(); + if (addr < 0x100) + { + // common registers 00nn + cmd[0] = 0; + cmd[1] = addr & 0xFF; + cmd[2] = 0x04; + } + else if (addr < 0x8000) + { + // socket registers 10nn, 11nn, 12nn, 13nn, etc + cmd[0] = 0; + cmd[1] = addr & 0xFF; + cmd[2] = ((addr >> 3) & 0xE0) | 0x0C; + } + else if (addr < 0xC000) + { + // transmit buffers 8000-87FF, 8800-8FFF, 9000-97FF, etc + // 10## #nnn nnnn nnnn + cmd[0] = addr >> 8; + cmd[1] = addr & 0xFF; + #if defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 1 + cmd[2] = 0x14; // 16K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 2 + cmd[2] = ((addr >> 8) & 0x20) | 0x14; // 8K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 4 + cmd[2] = ((addr >> 7) & 0x60) | 0x14; // 4K buffers + #else + cmd[2] = ((addr >> 6) & 0xE0) | 0x14; // 2K buffers + #endif + } + else + { + // receive buffers + cmd[0] = addr >> 8; + cmd[1] = addr & 0xFF; + #if defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 1 + cmd[2] = 0x1C; // 16K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 2 + cmd[2] = ((addr >> 8) & 0x20) | 0x1C; // 8K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 4 + cmd[2] = ((addr >> 7) & 0x60) | 0x1C; // 4K buffers + #else + cmd[2] = ((addr >> 6) & 0xE0) | 0x1C; // 2K buffers + #endif + } + + if (len <= 5) + { + for (uint8_t i=0; i < len; i++) + { + cmd[i + 3] = buf[i]; + } + + SPI.transfer(cmd, len + 3); + } + else + { + SPI.transfer(cmd, 3); +#ifdef SPI_HAS_TRANSFER_BUF + SPI.transfer(buf, NULL, len); +#else + // TODO: copy 8 bytes at a time to cmd[] and block transfer + for (uint16_t i=0; i < len; i++) + { + SPI.transfer(buf[i]); + } +#endif + } + resetSS(); + } + return len; +} + +uint16_t W5100Class::read(uint16_t addr, uint8_t *buf, uint16_t len) +{ + uint8_t cmd[4]; + + if (chip == 51) + { + for (uint16_t i=0; i < len; i++) + { + setSS(); + #if 1 + SPI.transfer(0x0F); + SPI.transfer(addr >> 8); + SPI.transfer(addr & 0xFF); + addr++; + buf[i] = SPI.transfer(0); + #else + cmd[0] = 0x0F; + cmd[1] = addr >> 8; + cmd[2] = addr & 0xFF; + cmd[3] = 0; + SPI.transfer(cmd, 4); // TODO: why doesn't this work? + buf[i] = cmd[3]; + addr++; + #endif + resetSS(); + } + } + else if (chip == 52) + { + setSS(); + cmd[0] = addr >> 8; + cmd[1] = addr & 0xFF; + cmd[2] = (len >> 8) & 0x7F; + cmd[3] = len & 0xFF; + SPI.transfer(cmd, 4); + memset(buf, 0, len); + SPI.transfer(buf, len); + resetSS(); + } + else + { + // chip == 55 + setSS(); + + if (addr < 0x100) + { + // common registers 00nn + cmd[0] = 0; + cmd[1] = addr & 0xFF; + cmd[2] = 0x00; + } + else if (addr < 0x8000) + { + // socket registers 10nn, 11nn, 12nn, 13nn, etc + cmd[0] = 0; + cmd[1] = addr & 0xFF; + cmd[2] = ((addr >> 3) & 0xE0) | 0x08; + } + else if (addr < 0xC000) + { + // transmit buffers 8000-87FF, 8800-8FFF, 9000-97FF, etc + // 10## #nnn nnnn nnnn + cmd[0] = addr >> 8; + cmd[1] = addr & 0xFF; + #if defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 1 + cmd[2] = 0x10; // 16K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 2 + cmd[2] = ((addr >> 8) & 0x20) | 0x10; // 8K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 4 + cmd[2] = ((addr >> 7) & 0x60) | 0x10; // 4K buffers + #else + cmd[2] = ((addr >> 6) & 0xE0) | 0x10; // 2K buffers + #endif + } else + { + // receive buffers + cmd[0] = addr >> 8; + cmd[1] = addr & 0xFF; + #if defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 1 + cmd[2] = 0x18; // 16K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 2 + cmd[2] = ((addr >> 8) & 0x20) | 0x18; // 8K buffers + #elif defined(ETHERNET_LARGE_BUFFERS) && MAX_SOCK_NUM <= 4 + cmd[2] = ((addr >> 7) & 0x60) | 0x18; // 4K buffers + #else + cmd[2] = ((addr >> 6) & 0xE0) | 0x18; // 2K buffers + #endif + } + SPI.transfer(cmd, 3); + memset(buf, 0, len); + SPI.transfer(buf, len); + resetSS(); + } + return len; +} + +void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) +{ + // Send command to socket + writeSnCR(s, _cmd); + // Wait for command to complete + while (readSnCR(s)) ; +} diff --git a/LibraryPatches/EthernetLarge/src/utility/w5100.h b/LibraryPatches/EthernetLarge/src/utility/w5100.h new file mode 100644 index 0000000..e5a71c0 --- /dev/null +++ b/LibraryPatches/EthernetLarge/src/utility/w5100.h @@ -0,0 +1,632 @@ +/**************************************************************************************************************************** + w5100.cpp - Driver for W5x00 + + EthernetWebServer is a library for the Ethernet shields to run WebServer + + Based on and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Built by Khoi Hoang https://github.com/khoih-prog/EthernetWebServer + Licensed under MIT license + Version: 1.0.9 + + Copyright 2018 Paul Stoffregen + Copyright (c) 2010 by Cristian Maglie + + This file is free software; you can redistribute it and/or modify + it under the terms of either the GNU General Public License version 2 + or the GNU Lesser General Public License version 2.1, both as + published by the Free Software Foundation. + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2020 Initial coding for Arduino Mega, Teensy, etc to support Ethernetx libraries + 1.0.1 K Hoang 20/02/2020 Add support to lambda functions + 1.0.2 K Hoang 20/02/2020 Add support to UIPEthernet library for ENC28J60 + 1.0.3 K Hoang 23/02/2020 Add support to SAM DUE / SAMD21 boards + 1.0.4 K Hoang 16/04/2020 Add support to SAMD51 boards + 1.0.5 K Hoang 24/04/2020 Add support to nRF52 boards, such as AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, + Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B30_ublox, etc. + More Custom Ethernet libraries supported such as Ethernet2, Ethernet3, EthernetLarge + 1.0.6 K Hoang 27/04/2020 Add support to ESP32/ESP8266 boards + 1.0.7 K Hoang 30/04/2020 Add ENC28J60 support to ESP32/ESP8266 boards + 1.0.8 K Hoang 12/05/2020 Fix W5x00 support for ESP8266 boards. + 1.0.9 K Hoang 15/05/2020 Add EthernetWrapper.h for easier W5x00 support as well as more Ethernet libs in the future. + *****************************************************************************************************************************/ + +// w5100.h contains private W5x00 hardware "driver" level definitions +// which are not meant to be exposed to other libraries or Arduino users + +#ifndef W5100_H_INCLUDED +#define W5100_H_INCLUDED + +#include +#include + +#ifndef USE_W5100 +#define USE_W5100 false +#else +#define USE_W5100 true +#endif + +#if !USE_W5100 + +// Safe for W5200 and W5500, but also tested OK on W5100 +// Use 14MHz if you know your W5100 can't run +// Higher SPI clock results in faster transfer to hosts on a LAN +// or with very low packet latency. With ordinary internet latency, +// the TCP window size & packet loss determine your overall speed. +#warning Use 25MHz clock for W5200/W5500. Not for W5100 +#define SPI_ETHERNET_SETTINGS SPISettings(25000000, MSBFIRST, SPI_MODE0) + +#else + +// Safe for all chips but too slow +#define SPI_ETHERNET_SETTINGS SPISettings(14000000, MSBFIRST, SPI_MODE0) +#warning Use 14MHz clock for W5100/W5200/W5500. Slow. + +#endif + + +// Require Ethernet.h, because we need MAX_SOCK_NUM +#ifndef ethernet_h_ +#error "EthernetLarge.h must be included before w5100.h" +#endif + + +// Arduino 101's SPI can not run faster than 8 MHz. +#if defined(ARDUINO_ARCH_ARC32) +#undef SPI_ETHERNET_SETTINGS +#define SPI_ETHERNET_SETTINGS SPISettings(8000000, MSBFIRST, SPI_MODE0) +#endif + +// Arduino Zero can't use W5100-based shields faster than 8 MHz +// https://github.com/arduino-libraries/Ethernet/issues/37#issuecomment-408036848 +// W5500 does seem to work at 12 MHz. Delete this if only using W5500 +#if defined(__SAMD21G18A__) +#undef SPI_ETHERNET_SETTINGS +//#warning Use SAMD21 architecture SPISettings(8000000, MSBFIRST, SPI_MODE3) => IP OK +#warning Use SAMD21 architecture SPISettings(30000000, MSBFIRST, SPI_MODE3) => IP OK +// Still not working !!! Original SPI_MODE0 not OK at all +//#define SPI_ETHERNET_SETTINGS SPISettings(8000000, MSBFIRST, SPI_MODE3) +#define SPI_ETHERNET_SETTINGS SPISettings(30000000, MSBFIRST, SPI_MODE3) +#endif + + +typedef uint8_t SOCKET; + +class SnMR { +public: + static const uint8_t CLOSE = 0x00; + static const uint8_t TCP = 0x21; + static const uint8_t UDP = 0x02; + static const uint8_t IPRAW = 0x03; + static const uint8_t MACRAW = 0x04; + static const uint8_t PPPOE = 0x05; + static const uint8_t ND = 0x20; + static const uint8_t MULTI = 0x80; +}; + +enum SockCMD { + Sock_OPEN = 0x01, + Sock_LISTEN = 0x02, + Sock_CONNECT = 0x04, + Sock_DISCON = 0x08, + Sock_CLOSE = 0x10, + Sock_SEND = 0x20, + Sock_SEND_MAC = 0x21, + Sock_SEND_KEEP = 0x22, + Sock_RECV = 0x40 +}; + +class SnIR { +public: + static const uint8_t SEND_OK = 0x10; + static const uint8_t TIMEOUT = 0x08; + static const uint8_t RECV = 0x04; + static const uint8_t DISCON = 0x02; + static const uint8_t CON = 0x01; +}; + +class SnSR { +public: + static const uint8_t CLOSED = 0x00; + static const uint8_t INIT = 0x13; + static const uint8_t LISTEN = 0x14; + static const uint8_t SYNSENT = 0x15; + static const uint8_t SYNRECV = 0x16; + static const uint8_t ESTABLISHED = 0x17; + static const uint8_t FIN_WAIT = 0x18; + static const uint8_t CLOSING = 0x1A; + static const uint8_t TIME_WAIT = 0x1B; + static const uint8_t CLOSE_WAIT = 0x1C; + static const uint8_t LAST_ACK = 0x1D; + static const uint8_t UDP = 0x22; + static const uint8_t IPRAW = 0x32; + static const uint8_t MACRAW = 0x42; + static const uint8_t PPPOE = 0x5F; +}; + +class IPPROTO { +public: + static const uint8_t IP = 0; + static const uint8_t ICMP = 1; + static const uint8_t IGMP = 2; + static const uint8_t GGP = 3; + static const uint8_t TCP = 6; + static const uint8_t PUP = 12; + static const uint8_t UDP = 17; + static const uint8_t IDP = 22; + static const uint8_t ND = 77; + static const uint8_t RAW = 255; +}; + +enum W5100Linkstatus { + UNKNOWN, + LINK_ON, + LINK_OFF +}; + +class W5100Class { + +public: + // KH + uint8_t init(uint8_t socketNumbers = MAX_SOCK_NUM, uint8_t new_ss_pin = 10); + + inline void setGatewayIp(const uint8_t * addr) { writeGAR(addr); } + inline void getGatewayIp(uint8_t * addr) { readGAR(addr); } + + inline void setSubnetMask(const uint8_t * addr) { writeSUBR(addr); } + inline void getSubnetMask(uint8_t * addr) { readSUBR(addr); } + + inline void setMACAddress(const uint8_t * addr) { writeSHAR(addr); } + inline void getMACAddress(uint8_t * addr) { readSHAR(addr); } + + inline void setIPAddress(const uint8_t * addr) { writeSIPR(addr); } + inline void getIPAddress(uint8_t * addr) { readSIPR(addr); } + + inline void setRetransmissionTime(uint16_t timeout) { writeRTR(timeout); } + inline void setRetransmissionCount(uint8_t retry) { writeRCR(retry); } + + static void execCmdSn(SOCKET s, SockCMD _cmd); + + + // W5100 Registers + // --------------- +//private: +public: + static uint16_t write(uint16_t addr, const uint8_t *buf, uint16_t len); + + static uint8_t write(uint16_t addr, uint8_t data) + { + return write(addr, &data, 1); + } + + static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len); + + static uint8_t read(uint16_t addr) + { + uint8_t data; + read(addr, &data, 1); + return data; + } + +#define __GP_REGISTER8(name, address) \ + static inline void write##name(uint8_t _data) { \ + write(address, _data); \ + } \ + static inline uint8_t read##name() { \ + return read(address); \ + } +#define __GP_REGISTER16(name, address) \ + static void write##name(uint16_t _data) { \ + uint8_t buf[2]; \ + buf[0] = _data >> 8; \ + buf[1] = _data & 0xFF; \ + write(address, buf, 2); \ + } \ + static uint16_t read##name() { \ + uint8_t buf[2]; \ + read(address, buf, 2); \ + return (buf[0] << 8) | buf[1]; \ + } +#define __GP_REGISTER_N(name, address, size) \ + static uint16_t write##name(const uint8_t *_buff) { \ + return write(address, _buff, size); \ + } \ + static uint16_t read##name(uint8_t *_buff) { \ + return read(address, _buff, size); \ + } + + // KH + W5100Linkstatus getLinkStatus(); + + +public: + __GP_REGISTER8 (MR, 0x0000); // Mode + __GP_REGISTER_N(GAR, 0x0001, 4); // Gateway IP address + __GP_REGISTER_N(SUBR, 0x0005, 4); // Subnet mask address + __GP_REGISTER_N(SHAR, 0x0009, 6); // Source MAC address + __GP_REGISTER_N(SIPR, 0x000F, 4); // Source IP address + __GP_REGISTER8 (IR, 0x0015); // Interrupt + __GP_REGISTER8 (IMR, 0x0016); // Interrupt Mask + __GP_REGISTER16(RTR, 0x0017); // Timeout address + __GP_REGISTER8 (RCR, 0x0019); // Retry count + __GP_REGISTER8 (RMSR, 0x001A); // Receive memory size (W5100 only) + __GP_REGISTER8 (TMSR, 0x001B); // Transmit memory size (W5100 only) + __GP_REGISTER8 (PATR, 0x001C); // Authentication type address in PPPoE mode + __GP_REGISTER8 (PTIMER, 0x0028); // PPP LCP Request Timer + __GP_REGISTER8 (PMAGIC, 0x0029); // PPP LCP Magic Number + __GP_REGISTER_N(UIPR, 0x002A, 4); // Unreachable IP address in UDP mode (W5100 only) + __GP_REGISTER16(UPORT, 0x002E); // Unreachable Port address in UDP mode (W5100 only) + __GP_REGISTER8 (VERSIONR_W5200,0x001F); // Chip Version Register (W5200 only) + __GP_REGISTER8 (VERSIONR_W5500,0x0039); // Chip Version Register (W5500 only) + __GP_REGISTER8 (PSTATUS_W5200, 0x0035); // PHY Status + __GP_REGISTER8 (PHYCFGR_W5500, 0x002E); // PHY Configuration register, default: 10111xxx + + +#undef __GP_REGISTER8 +#undef __GP_REGISTER16 +#undef __GP_REGISTER_N + + // W5100 Socket registers + // ---------------------- +private: + static uint16_t CH_BASE(void) { + //if (chip == 55) return 0x1000; + //if (chip == 52) return 0x4000; + //return 0x0400; + return CH_BASE_MSB << 8; + } + static uint8_t CH_BASE_MSB; // 1 redundant byte, saves ~80 bytes code on AVR + static const uint16_t CH_SIZE = 0x0100; + + static inline uint8_t readSn(SOCKET s, uint16_t addr) + { + return read(CH_BASE() + s * CH_SIZE + addr); + } + static inline uint8_t writeSn(SOCKET s, uint16_t addr, uint8_t data) + { + return write(CH_BASE() + s * CH_SIZE + addr, data); + } + static inline uint16_t readSn(SOCKET s, uint16_t addr, uint8_t *buf, uint16_t len) + { + return read(CH_BASE() + s * CH_SIZE + addr, buf, len); + } + static inline uint16_t writeSn(SOCKET s, uint16_t addr, uint8_t *buf, uint16_t len) + { + return write(CH_BASE() + s * CH_SIZE + addr, buf, len); + } + +#define __SOCKET_REGISTER8(name, address) \ + static inline void write##name(SOCKET _s, uint8_t _data) { \ + writeSn(_s, address, _data); \ + } \ + static inline uint8_t read##name(SOCKET _s) { \ + return readSn(_s, address); \ + } +#define __SOCKET_REGISTER16(name, address) \ + static void write##name(SOCKET _s, uint16_t _data) { \ + uint8_t buf[2]; \ + buf[0] = _data >> 8; \ + buf[1] = _data & 0xFF; \ + writeSn(_s, address, buf, 2); \ + } \ + static uint16_t read##name(SOCKET _s) { \ + uint8_t buf[2]; \ + readSn(_s, address, buf, 2); \ + return (buf[0] << 8) | buf[1]; \ + } +#define __SOCKET_REGISTER_N(name, address, size) \ + static uint16_t write##name(SOCKET _s, uint8_t *_buff) { \ + return writeSn(_s, address, _buff, size); \ + } \ + static uint16_t read##name(SOCKET _s, uint8_t *_buff) { \ + return readSn(_s, address, _buff, size); \ + } + +public: + __SOCKET_REGISTER8(SnMR, 0x0000) // Mode + __SOCKET_REGISTER8(SnCR, 0x0001) // Command + __SOCKET_REGISTER8(SnIR, 0x0002) // Interrupt + __SOCKET_REGISTER8(SnSR, 0x0003) // Status + __SOCKET_REGISTER16(SnPORT, 0x0004) // Source Port + __SOCKET_REGISTER_N(SnDHAR, 0x0006, 6) // Destination Hardw Addr + __SOCKET_REGISTER_N(SnDIPR, 0x000C, 4) // Destination IP Addr + __SOCKET_REGISTER16(SnDPORT, 0x0010) // Destination Port + __SOCKET_REGISTER16(SnMSSR, 0x0012) // Max Segment Size + __SOCKET_REGISTER8(SnPROTO, 0x0014) // Protocol in IP RAW Mode + __SOCKET_REGISTER8(SnTOS, 0x0015) // IP TOS + __SOCKET_REGISTER8(SnTTL, 0x0016) // IP TTL + __SOCKET_REGISTER8(SnRX_SIZE, 0x001E) // RX Memory Size (W5200 only) + __SOCKET_REGISTER8(SnTX_SIZE, 0x001F) // RX Memory Size (W5200 only) + __SOCKET_REGISTER16(SnTX_FSR, 0x0020) // TX Free Size + __SOCKET_REGISTER16(SnTX_RD, 0x0022) // TX Read Pointer + __SOCKET_REGISTER16(SnTX_WR, 0x0024) // TX Write Pointer + __SOCKET_REGISTER16(SnRX_RSR, 0x0026) // RX Free Size + __SOCKET_REGISTER16(SnRX_RD, 0x0028) // RX Read Pointer + __SOCKET_REGISTER16(SnRX_WR, 0x002A) // RX Write Pointer (supported?) + +#undef __SOCKET_REGISTER8 +#undef __SOCKET_REGISTER16 +#undef __SOCKET_REGISTER_N + + +private: + // KH + bool initialized = false; + static uint8_t chip; + static uint8_t ss_pin; + + static uint8_t isW5100(void); + static uint8_t isW5200(void); + static uint8_t isW5500(void); + +public: + // KH + static uint8_t softReset(void); + static uint8_t getChip(void) { return chip; } +#ifdef ETHERNET_LARGE_BUFFERS + static uint16_t SSIZE; + static uint16_t SMASK; +#else + static const uint16_t SSIZE = 2048; + static const uint16_t SMASK = 0x07FF; +#endif + static uint16_t SBASE(uint8_t socknum) + { + if (chip == 51) + { + return socknum * SSIZE + 0x4000; + } + else + { + return socknum * SSIZE + 0x8000; + } + } + + static uint16_t RBASE(uint8_t socknum) + { + if (chip == 51) { + return socknum * SSIZE + 0x6000; + } + else + { + return socknum * SSIZE + 0xC000; + } + } + + static bool hasOffsetAddressMapping(void) + { + if (chip == 55) + return true; + + return false; + } + + static void setSS(uint8_t pin) { ss_pin = pin; } + +private: +#if defined(__AVR__) + +#warning Use AVR architecture + + static volatile uint8_t *ss_pin_reg; + static uint8_t ss_pin_mask; + + inline static void initSS() + { + ss_pin_reg = portOutputRegister(digitalPinToPort(ss_pin)); + ss_pin_mask = digitalPinToBitMask(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg) &= ~ss_pin_mask; + } + + inline static void resetSS() + { + *(ss_pin_reg) |= ss_pin_mask; + } +#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__) + +#warning Use MK architecture + + static volatile uint8_t *ss_pin_reg; + + inline static void initSS() + { + ss_pin_reg = portOutputRegister(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg+256) = 1; + } + + inline static void resetSS() + { + *(ss_pin_reg+128) = 1; + } +#elif defined(__IMXRT1062__) + +#warning Use Teensy architecture + + static volatile uint32_t *ss_pin_reg; + static uint32_t ss_pin_mask; + + inline static void initSS() + { + ss_pin_reg = portOutputRegister(digitalPinToPort(ss_pin)); + ss_pin_mask = digitalPinToBitMask(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg+34) = ss_pin_mask; + } + + inline static void resetSS() + { + *(ss_pin_reg+33) = ss_pin_mask; + } +#elif defined(__MKL26Z64__) + static volatile uint8_t *ss_pin_reg; + static uint8_t ss_pin_mask; + inline static void initSS() + { + ss_pin_reg = portOutputRegister(digitalPinToPort(ss_pin)); + ss_pin_mask = digitalPinToBitMask(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg+8) = ss_pin_mask; + } + + inline static void resetSS() + { + *(ss_pin_reg+4) = ss_pin_mask; + } +#elif defined(__SAM3X8E__) || defined(__SAM3A8C__) || defined(__SAM3A4C__) + +#warning Use SAM3 architecture + + static volatile uint32_t *ss_pin_reg; + static uint32_t ss_pin_mask; + + inline static void initSS() + { + ss_pin_reg = &(digitalPinToPort(ss_pin)->PIO_PER); + ss_pin_mask = digitalPinToBitMask(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg+13) = ss_pin_mask; + } + + inline static void resetSS() + { + *(ss_pin_reg+12) = ss_pin_mask; + } +#elif defined(__PIC32MX__) + static volatile uint32_t *ss_pin_reg; + static uint32_t ss_pin_mask; + + inline static void initSS() + { + ss_pin_reg = portModeRegister(digitalPinToPort(ss_pin)); + ss_pin_mask = digitalPinToBitMask(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg+8+1) = ss_pin_mask; + } + + inline static void resetSS() + { + *(ss_pin_reg+8+2) = ss_pin_mask; + } + +#elif defined(ARDUINO_ARCH_ESP8266) + +#warning Use ARDUINO_ARCH_ESP8266 architecture + + static volatile uint32_t *ss_pin_reg; + static uint32_t ss_pin_mask; + + inline static void initSS() + { + ss_pin_reg = (volatile uint32_t*)GPO; + ss_pin_mask = 1 << ss_pin; + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + GPOC = ss_pin_mask; + } + + inline static void resetSS() + { + GPOS = ss_pin_mask; + } + +#elif defined(__SAMD21G18A__) + +#warning Use SAMD21 architecture + + static volatile uint32_t *ss_pin_reg; + static uint32_t ss_pin_mask; + + inline static void initSS() + { + ss_pin_reg = portModeRegister(digitalPinToPort(ss_pin)); + ss_pin_mask = digitalPinToBitMask(ss_pin); + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + *(ss_pin_reg+5) = ss_pin_mask; + } + + inline static void resetSS() + { + *(ss_pin_reg+6) = ss_pin_mask; + } +#else + +#warning Use Default architecture + + inline static void initSS() + { + pinMode(ss_pin, OUTPUT); + } + + inline static void setSS() + { + digitalWrite(ss_pin, LOW); + } + + inline static void resetSS() + { + digitalWrite(ss_pin, HIGH); + } +#endif +}; + +extern W5100Class W5100; + +#endif + +#ifndef UTIL_H +#define UTIL_H + +#ifndef htons +#define htons(x) ( (((x)<<8)&0xFF00) | (((x)>>8)&0xFF) ) +#endif + +#ifndef ntohs +#define ntohs(x) htons(x) +#endif + +#ifndef htonl +#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ + ((x)<< 8 & 0x00FF0000UL) | \ + ((x)>> 8 & 0x0000FF00UL) | \ + ((x)>>24 & 0x000000FFUL) ) +#endif + +#ifndef ntohl +#define ntohl(x) htonl(x) +#endif + +#endif //W5100_H_INCLUDED diff --git a/LibraryPatches/UIPEthernet-2.0.9/UIPEthernet.cpp b/LibraryPatches/UIPEthernet-2.0.9/UIPEthernet.cpp new file mode 100644 index 0000000..2af3cfb --- /dev/null +++ b/LibraryPatches/UIPEthernet-2.0.9/UIPEthernet.cpp @@ -0,0 +1,625 @@ +/* + UIPEthernet.cpp - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#if defined(ARDUINO) + #include +#endif +#if defined(__MBED__) + #include + #include "mbed/millis.h" +#endif +#include "UIPEthernet.h" +#include "utility/logging.h" +#include "utility/Enc28J60Network.h" + +#include "UIPUdp.h" + +extern "C" +{ +#include "utility/uipopt.h" +#include "utility/uip.h" +#include "utility/uip_arp.h" +} + +#define ETH_HDR ((struct uip_eth_hdr *)&uip_buf[0]) + +memhandle UIPEthernetClass::in_packet(NOBLOCK); +memhandle UIPEthernetClass::uip_packet(NOBLOCK); +uint8_t UIPEthernetClass::uip_hdrlen(0); +uint8_t UIPEthernetClass::packetstate(0); + +unsigned long UIPEthernetClass::periodic_timer; + +IPAddress UIPEthernetClass::_dnsServerAddress; +#if UIP_UDP + DhcpClass* UIPEthernetClass::_dhcp(NULL); + static DhcpClass s_dhcp; // Placing this instance here is saving 40K to final *.bin (see bug below) +#endif + +// Because uIP isn't encapsulated within a class we have to use global +// variables, so we can only have one TCP/IP stack per program. + +UIPEthernetClass::UIPEthernetClass() +{ +} + +void UIPEthernetClass::init(const uint8_t pin) +{ + ENC28J60ControlCS = pin; +} + +#if UIP_UDP +int +UIPEthernetClass::begin(const uint8_t* mac) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var _mac_address + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac, sizeof(_mac_address)); + ////// + + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac) DEBUG_V3:Function started")); + #endif + //static DhcpClass s_dhcp; // <-- this is a bug ! + // I leave it there commented for history. It is bring all GCC "new" memory allocation code, making the *.bin almost 40K bigger. I've move it globally. + _dhcp = &s_dhcp; + // Initialise the basic info + netInit(mac); + + // Now try to get our config info from a DHCP server + int ret = _dhcp->beginWithDHCP((uint8_t*)mac); + if(ret == 1) + { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + configure(_dhcp->getLocalIp(),_dhcp->getDnsServerIp(),_dhcp->getGatewayIp(),_dhcp->getSubnetMask()); + } + return ret; +} +#endif + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var _mac_address + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac, sizeof(_mac_address)); + ////// + + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip) DEBUG_V3:Function started")); + #endif + IPAddress dns = ip; + dns[3] = 1; + begin(mac, ip, dns); +} + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var _mac_address + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac, sizeof(_mac_address)); + ////// + + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns) DEBUG_V3:Function started")); + #endif + IPAddress gateway = ip; + gateway[3] = 1; + begin(mac, ip, dns, gateway); +} + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var _mac_address + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac, sizeof(_mac_address)); + ////// + + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway) DEBUG_V3:Function started")); + #endif + IPAddress subnet(255, 255, 255, 0); + begin(mac, ip, dns, gateway, subnet); +} + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var _mac_address + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac, sizeof(_mac_address)); + ////// + + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) DEBUG_V3:Function started")); + #endif + netInit(mac); + configure(ip,dns,gateway,subnet); +} + +int UIPEthernetClass::maintain(){ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::maintain() DEBUG_V3:Function started")); + #endif + tick(); + int rc = DHCP_CHECK_NONE; +#if UIP_UDP + if(_dhcp != NULL){ + //we have a pointer to dhcp, use it + rc = _dhcp->checkLease(); + switch ( rc ){ + case DHCP_CHECK_NONE: + //nothing done + break; + case DHCP_CHECK_RENEW_OK: + case DHCP_CHECK_REBIND_OK: + //we might have got a new IP. + configure(_dhcp->getLocalIp(),_dhcp->getDnsServerIp(),_dhcp->getGatewayIp(),_dhcp->getSubnetMask()); + break; + default: + //this is actually a error, it will retry though + break; + } + } + return rc; +#endif +} + +EthernetLinkStatus UIPEthernetClass::linkStatus() +{ + if (!Enc28J60Network::geterevid()) + return Unknown; + return Enc28J60Network::linkStatus() ? LinkON : LinkOFF; +} + +EthernetHardwareStatus UIPEthernetClass::hardwareStatus() { + if (!Enc28J60Network::geterevid()) + return EthernetNoHardware; + return EthernetENC28J60; +} + +IPAddress UIPEthernetClass::localIP() +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::localIP() DEBUG_V3:Function started")); + #endif + IPAddress ret; + uip_ipaddr_t a; + uip_gethostaddr(a); + return ip_addr_uip(a); +} + +IPAddress UIPEthernetClass::subnetMask() +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::subnetMask() DEBUG_V3:Function started")); + #endif + IPAddress ret; + uip_ipaddr_t a; + uip_getnetmask(a); + return ip_addr_uip(a); +} + +IPAddress UIPEthernetClass::gatewayIP() +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::gatewayIP() DEBUG_V3:Function started")); + #endif + IPAddress ret; + uip_ipaddr_t a; + uip_getdraddr(a); + return ip_addr_uip(a); +} + +IPAddress UIPEthernetClass::dnsServerIP() +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::dnsServerIP() DEBUG_V3:Function started")); + #endif + return _dnsServerAddress; +} + +void +UIPEthernetClass::tick() +{ +#if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::tick() DEBUG_V3:Function started")); +#endif +if (Enc28J60Network::geterevid()==0) + { + #if ACTLOGLEVEL>=LOG_ERR + LogObject.uart_send_strln(F("UIPEthernetClass::tick() ERROR:EREVID=0 -> Not found ENC28j60 device !! Function ended !!")); + #endif + return; + } +#if defined(ESP8266) + wdt_reset(); +#endif + if (in_packet == NOBLOCK) + { + in_packet = Enc28J60Network::receivePacket(); + #if ACTLOGLEVEL>=LOG_DEBUG + if (in_packet != NOBLOCK) + { + LogObject.uart_send_str(F("UIPEthernetClass::tick() DEBUG:receivePacket: ")); + LogObject.uart_send_decln(in_packet); + } + #endif + } + if (in_packet != NOBLOCK) + { + packetstate = UIPETHERNET_FREEPACKET; + uip_len = Enc28J60Network::blockSize(in_packet); + if (uip_len > 0) + { + Enc28J60Network::readPacket(in_packet,0,(uint8_t*)uip_buf,UIP_BUFSIZE); + if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_IP)) + { + uip_packet = in_packet; //required for upper_layer_checksum of in_packet! + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("UIPEthernetClass::tick() DEBUG:readPacket type IP, uip_len: ")); + LogObject.uart_send_decln(uip_len); + #endif + uip_arp_ipin(); + uip_input(); + if (uip_len > 0) + { + uip_arp_out(); + network_send(); + } + } + else if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_ARP)) + { + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("UIPEthernetClass::tick() DEBUG:readPacket type ARP, uip_len: ")); + LogObject.uart_send_decln(uip_len); + #endif + uip_arp_arpin(); + if (uip_len > 0) + { + network_send(); + } + } + } + if (in_packet != NOBLOCK && (packetstate & UIPETHERNET_FREEPACKET)) + { + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("UIPEthernetClass::tick() DEBUG:freeing packet: ")); + LogObject.uart_send_decln(in_packet); + #endif + Enc28J60Network::freePacket(); + in_packet = NOBLOCK; + } + } + + unsigned long now = millis(); + +#if UIP_CLIENT_TIMER >= 0 + bool periodic = (long)( now - periodic_timer ) >= 0; + for (int i = 0; i < UIP_CONNS; i++) + { +#else + if ((long)( now - periodic_timer ) >= 0) + { + periodic_timer = now + UIP_PERIODIC_TIMER; + + for (int i = 0; i < UIP_CONNS; i++) + { +#endif + + uip_conn = &uip_conns[i]; + +#if UIP_CLIENT_TIMER >= 0 + if (periodic) + { +#endif + + uip_process(UIP_TIMER); + +#if UIP_CLIENT_TIMER >= 0 + } + else + { + if (((uip_userdata_t*)uip_conn->appstate)!=NULL) + { + if ((long)( now - ((uip_userdata_t*)uip_conn->appstate)->timer) >= 0) + { + uip_process(UIP_POLL_REQUEST); + ((uip_userdata_t*)uip_conn->appstate)->timer = millis() + UIP_CLIENT_TIMER; + } + else + { + continue; + } + } + else + continue; + } +#endif + // If the above function invocation resulted in data that + // should be sent out on the Enc28J60Network, the global variable + // uip_len is set to a value > 0. + if (uip_len > 0) + { + uip_arp_out(); + network_send(); + } + } +#if UIP_CLIENT_TIMER >= 0 + if (periodic) + { + periodic_timer = now + UIP_PERIODIC_TIMER; +#endif +#if UIP_UDP + for (int i = 0; i < UIP_UDP_CONNS; i++) + { + uip_udp_periodic(i); + // If the above function invocation resulted in data that + // should be sent out on the Enc28J60Network, the global variable + // uip_len is set to a value > 0. */ + if (uip_len > 0) + { + UIPUDP::_send((uip_udp_userdata_t *)(uip_udp_conns[i].appstate)); + } + } +#endif /* UIP_UDP */ + } +} + +bool UIPEthernetClass::network_send() +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::network_send() DEBUG_V3:Function started")); + #endif + if (packetstate & UIPETHERNET_SENDPACKET) + { +#if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("UIPEthernetClass::network_send() DEBUG:uip_packet: ")); + LogObject.uart_send_dec(uip_packet); + LogObject.uart_send_str(F(", hdrlen: ")); + LogObject.uart_send_decln(uip_hdrlen); +#endif + Enc28J60Network::writePacket(uip_packet, UIP_SENDBUFFER_OFFSET,uip_buf,uip_hdrlen); + packetstate &= ~ UIPETHERNET_SENDPACKET; + goto sendandfree; + } + uip_packet = Enc28J60Network::allocBlock(uip_len + UIP_SENDBUFFER_OFFSET + UIP_SENDBUFFER_PADDING); + if (uip_packet != NOBLOCK) + { +#if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("UIPEthernetClass::network_send() DEBUG:uip_buf (uip_len): ")); + LogObject.uart_send_dec(uip_len); + LogObject.uart_send_str(F(", packet: ")); + LogObject.uart_send_decln(uip_packet); +#endif + Enc28J60Network::writePacket(uip_packet, UIP_SENDBUFFER_OFFSET,uip_buf,uip_len); + goto sendandfree; + } + return false; +sendandfree: + bool success = Enc28J60Network::sendPacket(uip_packet); + Enc28J60Network::freeBlock(uip_packet); + uip_packet = NOBLOCK; + return success; +} + +void UIPEthernetClass::netInit(const uint8_t* mac) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::netInit(const uint8_t* mac) DEBUG_V3:Function started")); + #endif + periodic_timer = millis() + UIP_PERIODIC_TIMER; + + Enc28J60Network::init((uint8_t*)mac); + uip_seteth_addr(mac); + + uip_init(); + uip_arp_init(); +} + +void UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) DEBUG_V3:Function started")); + #endif + uip_ipaddr_t ipaddr; + + uip_ip_addr(ipaddr, ip); + uip_sethostaddr(ipaddr); + + uip_ip_addr(ipaddr, gateway); + uip_setdraddr(ipaddr); + + uip_ip_addr(ipaddr, subnet); + uip_setnetmask(ipaddr); + + _dnsServerAddress = dns; +} + +UIPEthernetClass UIPEthernet; + +/*---------------------------------------------------------------------------*/ +uint16_t +UIPEthernetClass::chksum(uint16_t sum, const uint8_t *data, uint16_t len) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::chksum(uint16_t sum, const uint8_t *data, uint16_t len) DEBUG_V3:Function started")); + #endif + uint16_t t; + const uint8_t *dataptr; + const uint8_t *last_byte; + + dataptr = data; + last_byte = data + len - 1; + + while(dataptr < last_byte) { /* At least two more bytes */ + t = (dataptr[0] << 8) + dataptr[1]; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + dataptr += 2; + } + + if(dataptr == last_byte) { + t = (dataptr[0] << 8) + 0; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + } + + /* Return sum in host byte order. */ + return sum; +} + +/*---------------------------------------------------------------------------*/ + +uint16_t +UIPEthernetClass::ipchksum(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::ipchksum(void) DEBUG_V3:Function started")); + #endif + uint16_t sum; + + sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); + return (sum == 0) ? 0xffff : htons(sum); +} + +/*---------------------------------------------------------------------------*/ +uint16_t +#if UIP_UDP +UIPEthernetClass::upper_layer_chksum(uint8_t proto) +#else +uip_tcpchksum(void) +#endif +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + #if UIP_UDP + LogObject.uart_send_strln(F("UIPEthernetClass::upper_layer_chksum(uint8_t proto) DEBUG_V3:Function started")); + #else + LogObject.uart_send_strln(F("uip_tcpchksum(void) INFO:Function started")); + #endif + #endif + uint16_t upper_layer_len; + uint16_t sum; + +#if UIP_CONF_IPV6 + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]); +#else /* UIP_CONF_IPV6 */ + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN; +#endif /* UIP_CONF_IPV6 */ + + /* First sum pseudoheader. */ + + /* IP protocol and length fields. This addition cannot carry. */ +#if UIP_UDP + sum = upper_layer_len + proto; +#else + sum = upper_layer_len + UIP_PROTO_TCP; +#endif + /* Sum IP source and destination addresses. */ + sum = UIPEthernetClass::chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); + + uint8_t upper_layer_memlen; +#if UIP_UDP + switch(proto) + { +// case UIP_PROTO_ICMP: +// case UIP_PROTO_ICMP6: +// upper_layer_memlen = upper_layer_len; +// break; + case UIP_PROTO_UDP: + upper_layer_memlen = UIP_UDPH_LEN; + break; + default: +// case UIP_PROTO_TCP: +#endif + upper_layer_memlen = (BUF->tcpoffset >> 4) << 2; +#if UIP_UDP + break; + } +#endif + sum = UIPEthernetClass::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen); +#if ACTLOGLEVEL>=LOG_DEBUG + #if UIP_UDP + LogObject.uart_send_str(F("UIPEthernetClass::upper_layer_chksum(uint8_t proto) DEBUG:uip_buf[")); + #else + LogObject.uart_send_str(F("uip_tcpchksum(void) DEBUG:uip_buf[")); + #endif + LogObject.uart_send_dec(UIP_IPH_LEN + UIP_LLH_LEN); + LogObject.uart_send_str(F("-")); + LogObject.uart_send_dec(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); + LogObject.uart_send_str(F("]: ")); + LogObject.uart_send_hexln(htons(sum)); +#endif + if (upper_layer_memlen < upper_layer_len) + { + sum = Enc28J60Network::chksum( + sum, + UIPEthernetClass::uip_packet, + (UIPEthernetClass::packetstate & UIPETHERNET_SENDPACKET ? UIP_IPH_LEN + UIP_LLH_LEN + UIP_SENDBUFFER_OFFSET : UIP_IPH_LEN + UIP_LLH_LEN) + upper_layer_memlen, + upper_layer_len - upper_layer_memlen + ); +#if ACTLOGLEVEL>=LOG_DEBUG + #if UIP_UDP + LogObject.uart_send_str(F("UIPEthernetClass::upper_layer_chksum(uint8_t proto) DEBUG:uip_packet(")); + #else + LogObject.uart_send_str(F("uip_tcpchksum(void) DEBUG:uip_packet(")); + #endif + LogObject.uart_send_dec(UIPEthernetClass::uip_packet); + LogObject.uart_send_str(F(")[")); + LogObject.uart_send_dec(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); + LogObject.uart_send_str(F("-")); + LogObject.uart_send_dec(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_len); + LogObject.uart_send_str(F("]: ")); + LogObject.uart_send_hexln(htons(sum)); +#endif + } + return (sum == 0) ? 0xffff : htons(sum); +} + +uint16_t +uip_ipchksum(void) +{ + return UIPEthernet.ipchksum(); +} + +#if UIP_UDP +uint16_t +uip_tcpchksum(void) +{ + uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_TCP); + return sum; +} + +uint16_t +uip_udpchksum(void) +{ + uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_UDP); + return sum; +} +#endif diff --git a/LibraryPatches/UIPEthernet-2.0.9/UIPEthernet.h b/LibraryPatches/UIPEthernet-2.0.9/UIPEthernet.h new file mode 100644 index 0000000..4d3e0eb --- /dev/null +++ b/LibraryPatches/UIPEthernet-2.0.9/UIPEthernet.h @@ -0,0 +1,166 @@ +/* + UIPEthernet.h - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef UIPETHERNET_H +#define UIPETHERNET_H + +#include "ethernet_comp.h" +#if defined(__MBED__) + #include +#endif +#if defined(ARDUINO) + #include + #if defined(__STM32F3__) || (!defined(ARDUINO_ARCH_STM32) && defined(STM32F3)) || defined(__RFduino__) + #include "mbed/IPAddress.h" + #else + #include "IPAddress.h" + #endif +#endif +#include "utility/Enc28J60Network.h" +#include "utility/uipopt.h" +#include "Dhcp.h" +#if UIP_UDP + #include "UIPUdp.h" +#endif +#include "UIPClient.h" +#include "UIPServer.h" + +extern "C" +{ +#include "utility/uip.h" +} + +#define UIPETHERNET_FREEPACKET 1 +#define UIPETHERNET_SENDPACKET 2 +#define UIPETHERNET_BUFFERREAD 4 + +#define uip_ip_addr(addr, ip) do { \ + ((u16_t *)(addr))[0] = HTONS(((ip[0]) << 8) | (ip[1])); \ + ((u16_t *)(addr))[1] = HTONS(((ip[2]) << 8) | (ip[3])); \ + } while(0) + +#define ip_addr_uip(a) IPAddress(a[0] & 0xFF, a[0] >> 8 , a[1] & 0xFF, a[1] >> 8) //TODO this is not IPV6 capable + +#define uip_seteth_addr(eaddr) do {uip_ethaddr.addr[0] = eaddr[0]; \ + uip_ethaddr.addr[1] = eaddr[1];\ + uip_ethaddr.addr[2] = eaddr[2];\ + uip_ethaddr.addr[3] = eaddr[3];\ + uip_ethaddr.addr[4] = eaddr[4];\ + uip_ethaddr.addr[5] = eaddr[5];} while(0) + +#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +enum EthernetLinkStatus { + Unknown, + LinkON, + LinkOFF +}; + +enum EthernetHardwareStatus { + EthernetNoHardware, + EthernetW5100, + EthernetW5200, + EthernetW5500, + EthernetENC28J60 = 10 +}; + +class UIPEthernetClass +{ +public: + UIPEthernetClass(); + + void init(const uint8_t pin); + + int begin(const uint8_t* mac); + void begin(const uint8_t* mac, IPAddress ip); + void begin(const uint8_t* mac, IPAddress ip, IPAddress dns); + void begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway); + void begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); + + // maintain() must be called at regular intervals to process the incoming serial + // data and issue IP events to the sketch. It does not return until all IP + // events have been processed. Renews dhcp-lease if required. + int maintain(); + + EthernetLinkStatus linkStatus(); + EthernetHardwareStatus hardwareStatus(); + + // KH add to have similar function to Ethernet lib + // Certainly we can use void macAddress(uint8_t mac[]) to read from W5x00. + void MACAddress(uint8_t *mac_address) + { + memcpy(mac_address, _mac_address, sizeof(_mac_address)); + } + ////// + + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP(); + +private: + + // KH add to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + uint8_t _mac_address[6] ={0,}; + ////// + + static memhandle in_packet; + static memhandle uip_packet; + static uint8_t uip_hdrlen; + static uint8_t packetstate; + + static IPAddress _dnsServerAddress; + #if UIP_UDP + static DhcpClass* _dhcp; + #endif + static unsigned long periodic_timer; + + static void netInit(const uint8_t* mac); + static void configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); + + static void tick(); + + static bool network_send(); + + friend class UIPServer; + + friend class UIPClient; + + friend class UIPUDP; + + static uint16_t chksum(uint16_t sum, const uint8_t* data, uint16_t len); + static uint16_t ipchksum(void); +#if UIP_UDP + static uint16_t upper_layer_chksum(uint8_t proto); +#endif + friend uint16_t uip_ipchksum(void); + friend uint16_t uip_tcpchksum(void); + friend uint16_t uip_udpchksum(void); + + friend void uipclient_appcall(void); + friend void uipudp_appcall(void); + +#if UIP_CONF_IPV6 + uint16_t uip_icmp6chksum(void); +#endif /* UIP_CONF_IPV6 */ +}; + +extern UIPEthernetClass UIPEthernet; + +#endif diff --git a/LibraryPatches/UIPEthernet-2.0.9/utility/Enc28J60Network.cpp b/LibraryPatches/UIPEthernet-2.0.9/utility/Enc28J60Network.cpp new file mode 100644 index 0000000..8c405d6 --- /dev/null +++ b/LibraryPatches/UIPEthernet-2.0.9/utility/Enc28J60Network.cpp @@ -0,0 +1,1216 @@ +/* + Enc28J60NetworkClass.h + UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. + + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + based on enc28j60.c file from the AVRlib library by Pascal Stang. + For AVRlib See http://www.procyonengineering.com/ + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "Enc28J60Network.h" +#if defined(ARDUINO) + #include "Arduino.h" +#endif +#if defined(__MBED__) + #include + #include "mbed/millis.h" + #define delay(x) wait_ms(x) +#endif +#include "logging.h" + +// KH, For nRF52 +//#define ENC28J60_USE_SPILIB true + +uint8_t ENC28J60ControlCS = ENC28J60_CONTROL_CS; + +#if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + #if defined(STM32F2) + #include + #elif (defined(ARDUINO_ARCH_STM32) || !defined(STM32F3)) && !defined(__STM32F4__) + #include + extern SPIClass SPI; + //#elif defined(ARDUINO_ARCH_AMEBA) + //SPIClass SPI((void *)(&spi_obj), 11, 12, 13, 10); + //SPI _spi(SPI_MOSI,SPI_MISO,SPI_SCK,ENC28J60ControlCS); + #else + #include "HardwareSPI.h" + extern HardwareSPI SPI(1); + #endif + #endif + #if defined(__MBED__) + SPI _spi(SPI_MOSI,SPI_MISO,SPI_SCK); + DigitalOut _cs(ENC28J60ControlCS); + Serial LogObject(SERIAL_TX,SERIAL_RX); + #endif +#endif + +extern "C" { + #if defined(ARDUINO_ARCH_AVR) + // AVR-specific code + #include + #elif defined(ARDUINO_ARCH_SAM) + // SAM-specific code + #elif defined(ARDUINO_ARCH_SAMD) + // SAMD-specific code + #else + // generic, non-platform specific code + #endif +#include "enc28j60.h" +#include "uip.h" +} + +#if defined(ARDUINO) + // set CS to 0 = active + #define CSACTIVE digitalWrite(ENC28J60ControlCS, LOW) + // set CS to 1 = passive + #define CSPASSIVE digitalWrite(ENC28J60ControlCS, HIGH) +#endif +#if defined(__MBED__) + // set CS to 0 = active + #define CSACTIVE _cs=0 + // set CS to 1 = passive + #define CSPASSIVE _cs=1 +#endif + +// +#if defined(ARDUINO_ARCH_AVR) +#define waitspi() while(!(SPSR&(1<=LOG_DEBUG + LogObject.uart_send_str(F("ENC28J60::init DEBUG:csPin = ")); + LogObject.uart_send_decln(ENC28J60ControlCS); + LogObject.uart_send_str(F("ENC28J60::init DEBUG:miso = ")); + LogObject.uart_send_decln(SPI_MISO); + LogObject.uart_send_str(F("ENC28J60::init DEBUG:mosi = ")); + LogObject.uart_send_decln(SPI_MOSI); + LogObject.uart_send_str(F("ENC28J60::init DEBUG:sck = ")); + LogObject.uart_send_decln(SPI_SCK); + #endif +#if ENC28J60_USE_SPILIB + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_strln(F("ENC28J60::init DEBUG:Use SPI lib SPI.begin()")); + #endif + #if defined(ARDUINO) + #if defined(__STM32F3__) || (!defined(ARDUINO_ARCH_STM32) && defined(STM32F3)) || defined(__STM32F4__) + SPI.begin(SPI_9MHZ, MSBFIRST, 0); + #else + SPI.begin(); + #endif + #endif + #if defined(ARDUINO_ARCH_AVR) + // AVR-specific code + SPI.setClockDivider(SPI_CLOCK_DIV2); //results in 8MHZ at 16MHZ system clock. + #elif defined(ARDUINO_ARCH_SAM) + // SAM-specific code + SPI.setClockDivider(10); //defaults to 21 which results in aprox. 4MHZ. A 10 should result in a little more than 8MHZ. + #elif defined(ARDUINO_ARCH_SAMD) + // SAMD-specific code + // Should we set clock divider? + SPI.setClockDivider(10); + #elif defined(__STM32F1__) || defined(__STM32F3__) + // generic, non-platform specific code + #define USE_STM32F1_DMAC 1 //on STM32 + // BOARD_NR_SPI >= 1 BOARD_SPI1_NSS_PIN, BOARD_SPI1_SCK_PIN, BOARD_SPI1_MISO_PIN, BOARD_SPI1_MOSI_PIN + SPI.setBitOrder(MSBFIRST); + SPI.setDataMode(SPI_MODE0); + SPI.setClockDivider(SPI_CLOCK_DIV8); //value 8 the result is 9MHz at 72MHz clock. + #else + #if defined(ARDUINO) + #if !defined(__STM32F3__) && !defined(STM32F3) && !defined(__STM32F4__) + SPI.setBitOrder(MSBFIRST); + #endif + //Settings for ESP8266 + //SPI.setDataMode(SPI_MODE0); + //SPI.setClockDivider(SPI_CLOCK_DIV16); + #endif + #if defined(__MBED__) + _spi.format(8, 0); // 8bit, mode 0 + _spi.frequency(7000000); // 7MHz + #endif + #endif +#else + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_strln(F("ENC28J60::init DEBUG:Use Native hardware SPI")); + #endif + pinMode(SPI_MOSI, OUTPUT); + pinMode(SPI_SCK, OUTPUT); + pinMode(SPI_MISO, INPUT); + //Hardware SS must be configured as OUTPUT to enable SPI-master (regardless of which pin is configured as ENC28J60ControlCS) + pinMode(SS, OUTPUT); + digitalWrite(SS,HIGH); + + digitalWrite(SPI_MOSI, LOW); + digitalWrite(SPI_SCK, LOW); + + // initialize SPI interface + // master mode and Fosc/2 clock: + SPCR = (1<=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:Before readOp(ENC28J60_READ_CTRL_REG, ESTAT)")); + #endif + nextPacketPtr = RXSTART_INIT; + while ((!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY) && (timeout>0)) + { + timeout=timeout-1; + delay(10); + #if defined(ESP8266) + wdt_reset(); + #endif + } + #if ACTLOGLEVEL>=LOG_ERR + if (timeout==0) {LogObject.uart_send_strln(F("ENC28J60::init ERROR:TIMEOUT !!"));} + #endif + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:After readOp(ENC28J60_READ_CTRL_REG, ESTAT)")); + #endif + // Rx start + writeRegPair(ERXSTL, RXSTART_INIT); + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:After writeRegPair(ERXSTL, RXSTART_INIT)")); + #endif + // set receive pointer address + writeRegPair(ERXRDPTL, RXSTART_INIT); + // RX end + writeRegPair(ERXNDL, RXSTOP_INIT); + // TX start + //writeRegPair(ETXSTL, TXSTART_INIT); + // TX end + //writeRegPair(ETXNDL, TXSTOP_INIT); + // do bank 1 stuff, packet filter: + // For broadcast packets we allow only ARP packtets + // All other packets should be unicast only for our mac (MAADR) + // + // The pattern to match on is therefore + // Type ETH.DST + // ARP BROADCAST + // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9 + // in binary these poitions are:11 0000 0011 1111 + // This is hex 303F->EPMM0=0x3f,EPMM1=0x30 + //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN! +// enableBroadcast(); // change to add ERXFCON_BCEN recommended by epam + writeReg(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN); + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:After writeReg(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN)")); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + writeRegPair(EPMM0, 0x303f); + writeRegPair(EPMCSL, 0xf7f9); + // + // + // do bank 2 stuff + // enable MAC receive + // and bring MAC out of reset (writes 0x00 to MACON2) + writeRegPair(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); + // enable automatic padding to 60bytes and CRC operations + writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:After writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN)")); + #endif + // set inter-frame gap (non-back-to-back) + writeRegPair(MAIPGL, 0x0C12); + // set inter-frame gap (back-to-back) + writeReg(MABBIPG, 0x12); + // Set the maximum packet size which the controller will accept + // Do not send packets longer than MAX_FRAMELEN: + writeRegPair(MAMXFLL, MAX_FRAMELEN); + // do bank 3 stuff + // write MAC address + // NOTE: MAC address in ENC28J60 is byte-backward + writeReg(MAADR5, macaddr[0]); + writeReg(MAADR4, macaddr[1]); + writeReg(MAADR3, macaddr[2]); + writeReg(MAADR2, macaddr[3]); + writeReg(MAADR1, macaddr[4]); + writeReg(MAADR0, macaddr[5]); + // no loopback of transmitted frames + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:Before phyWrite(PHCON2, PHCON2_HDLDIS)")); + #endif + phyWrite(PHCON2, PHCON2_HDLDIS); + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:After phyWrite(PHCON2, PHCON2_HDLDIS)")); + #endif + // switch to bank 0 + setBank(ECON1); + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:After setBank(ECON1)")); + #endif + // enable interrutps + writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE); + // enable packet reception + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + //Configure leds + phyWrite(PHLCON,0x476); + + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:Before readReg(EREVID);")); + #endif + erevid=readReg(EREVID); + if (erevid==0xFF) {erevid=0;} + // microchip forgot to step the number on the silcon when they + // released the revision B7. 6 is now rev B7. We still have + // to see what they do when they release B8. At the moment + // there is no B8 out yet + //if (erevid > 5) ++erevid; + #if ACTLOGLEVEL>=LOG_INFO + LogObject.uart_send_str(F("ENC28J60::init INFO: Chip erevid=")); + LogObject.uart_send_dec(erevid); + LogObject.uart_send_strln(F(" initialization completed.")); + #endif + +// return Enc28J60Network::erevid; +} + +memhandle +Enc28J60Network::receivePacket(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::receivePacket(void) DEBUG_V3:Function started")); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + uint8_t rxstat; + uint16_t len; + // check if a packet has been received and buffered + //if( !(readReg(EIR) & EIR_PKTIF) ){ + // The above does not work. See Rev. B4 Silicon Errata point 6. + #if ACTLOGLEVEL>=LOG_ERR + if (erevid==0) + { + LogObject.uart_send_strln(F("Enc28J60Network::receivePacket(void) ERROR:ENC28j50 Device not found !! Bypass receivePacket function !!")); + } + #endif + uint8_t epktcnt=readReg(EPKTCNT); + if ((erevid!=0) && (epktcnt!=0)) + { + uint16_t readPtr = nextPacketPtr+6 > RXSTOP_INIT ? nextPacketPtr+6-((RXSTOP_INIT + 1)-RXSTART_INIT) : nextPacketPtr+6; + // Set the read pointer to the start of the received packet + writeRegPair(ERDPTL, nextPacketPtr); + // read the next packet pointer + nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0); + nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; + // read the packet length (see datasheet page 43) + len = readOp(ENC28J60_READ_BUF_MEM, 0); + len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; + len -= 4; //remove the CRC count + // read the receive status (see datasheet page 43) + rxstat = readOp(ENC28J60_READ_BUF_MEM, 0); + //rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("Enc28J60Network::receivePacket(void) DEBUG:receivePacket [")); + LogObject.uart_send_hex(readPtr); + LogObject.uart_send_str(F("-")); + LogObject.uart_send_hex((readPtr+len) % (RXSTOP_INIT+1)); + LogObject.uart_send_str(F("], next: ")); + LogObject.uart_send_hex(nextPacketPtr); + LogObject.uart_send_str(F(", stat: ")); + LogObject.uart_send_hex(rxstat); + LogObject.uart_send_str(F(", Packet count: ")); + LogObject.uart_send_dec(epktcnt); + LogObject.uart_send_str(F(" -> ")); + LogObject.uart_send_strln((rxstat & 0x80)!=0 ? "OK" : "failed"); + #endif + // decrement the packet counter indicate we are done with this packet + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); + // check CRC and symbol errors (see datasheet page 44, table 7-3): + // The ERXFCON.CRCEN is set by default. Normally we should not + // need to check this. + if (((rxstat & 0x80) != 0) && (nextPacketPtr<=RXSTOP_INIT)) + { + receivePkt.begin = readPtr; + receivePkt.size = len; + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("Enc28J60Network::receivePacket(void) DEBUG: rxstat OK. receivePkt.size=")); + LogObject.uart_send_decln(len); + #endif + return UIP_RECEIVEBUFFERHANDLE; + } + // Move the RX read pointer to the start of the next received packet + // This frees the memory we just read out + setERXRDPT(); + } + return (NOBLOCK); +} + +void +Enc28J60Network::setERXRDPT(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::setERXRDPT(void) DEBUG_V3:Function started")); + #endif + // Make sure the value is odd. See Rev. B1,B4,B5,B7 Silicon Errata issues 14 + uint16_t actnextPacketPtr = nextPacketPtr == RXSTART_INIT ? RXSTOP_INIT : nextPacketPtr-1; + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("Enc28J60Network::setERXRDPT(void) DEBUG:Set actnextPacketPtr:")); + LogObject.uart_send_hexln(actnextPacketPtr); + #endif + // datasheet: The ENC28J60 will always write up to, but not including + writeRegPair(ERXRDPTL, actnextPacketPtr); +} + +memaddress +Enc28J60Network::blockSize(memhandle handle) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::blockSize(memhandle handle) DEBUG_V3:Function started")); + #endif + return ((handle == NOBLOCK) || (erevid==0)) ? 0 : handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size; +} + +bool +Enc28J60Network::sendPacket(memhandle handle) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::sendPacket(memhandle handle) INFO:Function started")); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + if (erevid==0) + { + #if ACTLOGLEVEL>=LOG_ERR + LogObject.uart_send_strln(F("Enc28J60Network::sendPacket(memhandle handle) ERROR:ENC28j50 Device not found !! Bypass sendPacket function !!")); + #endif + return false; + } + + memblock *packet = &blocks[handle]; + uint16_t start = packet->begin; // includes the UIP_SENDBUFFER_OFFSET for control byte + uint16_t end = start + packet->size - 1 - UIP_SENDBUFFER_PADDING; // end = start + size - 1 and padding for TSV is no included + + // write control-byte (if not 0 anyway) + writeByte(start, 0); + + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("Enc28J60Network::sendPacket(memhandle handle) DEBUG:sendPacket(")); + LogObject.uart_send_dec(handle); + LogObject.uart_send_str(F(") [")); + LogObject.uart_send_hex(start); + LogObject.uart_send_str(F("-")); + LogObject.uart_send_hex(end); + LogObject.uart_send_str(F("]: ")); + for (uint16_t i=start; i<=end; i++) + { + LogObject.uart_send_hex(readByte(i)); + LogObject.uart_send_str(F(" ")); + } + LogObject.uart_send_strln(F("")); + #endif + + // TX start + writeRegPair(ETXSTL, start); + // Set the TXND pointer to correspond to the packet size given + writeRegPair(ETXNDL, end); + + bool success = false; + // See Rev. B7 Silicon Errata issues 12 and 13 + for (uint8_t retry = 0; retry < TX_COLLISION_RETRY_COUNT; retry++) + { + // Reset the transmit logic problem. Errata 12 + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST); + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST); + writeOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF | EIR_TXIF); + + // send the contents of the transmit buffer onto the network + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); + + uint8_t eir; + // wait for transmission to complete or fail + while (((eir = readReg(EIR)) & (EIR_TXIF | EIR_TXERIF)) == 0); + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS); + success = ((eir & EIR_TXERIF) == 0); + if (success) + break; // usual exit of the for(retry) loop + + // Errata 13 detection + uint8_t tsv4 = readByte(end + 4); + if (!(tsv4 & 0b00100000)) // is it "late collision" indicated in bit 29 of TSV? + break; // other fail, not the Errata 13 situation + #if ACTLOGLEVEL>=LOG_ERROR + LogObject.uart_send_strln(F("Enc28J60Network::sendPacket(memhandle handle) Errata 13 LATE COLLISION !!")); + #endif + } + + return success; +} + +uint16_t +Enc28J60Network::setReadPtr(memhandle handle, memaddress position, uint16_t len) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::setReadPtr(memhandle handle, memaddress position, uint16_t len) DEBUG_V3:Function started")); + #endif + memblock *packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle]; + memaddress start = handle == UIP_RECEIVEBUFFERHANDLE && packet->begin + position > RXSTOP_INIT ? packet->begin + position-((RXSTOP_INIT + 1)-RXSTART_INIT) : packet->begin + position; + + writeRegPair(ERDPTL, start); + + if (len > packet->size - position) + len = packet->size - position; + return len; +} + +uint16_t +Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) DEBUG_V3:Function started")); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + len = setReadPtr(handle, position, len); + readBuffer(len, buffer); + #if ACTLOGLEVEL>=LOG_DEBUG_V2 + LogObject.uart_send_str(F("Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) DEBUG_V2: Read bytes:")); + LogObject.uart_send_dec(len); + LogObject.uart_send_str(F(" save to block(")); + LogObject.uart_send_dec(handle); + LogObject.uart_send_str(F(") [")); + LogObject.uart_send_hex(position); + LogObject.uart_send_str(F("]: ")); + for (uint16_t i=0; i=LOG_DEBUG_V3 + LogObject.uart_send_str(F("Enc28J60Network::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) DEBUG_V3:Function started with len:")); + LogObject.uart_send_decln(len); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + memblock *packet = &blocks[handle]; + uint16_t start = packet->begin + position; + + writeRegPair(EWRPTL, start); + + if (len > packet->size - position) + len = packet->size - position; + writeBuffer(len, buffer); + #if ACTLOGLEVEL>=LOG_DEBUG_V2 + LogObject.uart_send_str(F("Enc28J60Network::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) DEBUG_V2: Write bytes:")); + LogObject.uart_send_dec(len); + LogObject.uart_send_str(F(" save to block(")); + LogObject.uart_send_dec(handle); + LogObject.uart_send_str(F(") [")); + LogObject.uart_send_hex(start); + LogObject.uart_send_str(F("]: ")); + for (uint16_t i=0; i=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::enableBroadcast (bool temporary) DEBUG_V3:Function started")); + #endif + writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_BCEN); + if(!temporary) + broadcast_enabled = true; +} + +void Enc28J60Network::disableBroadcast (bool temporary) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::disableBroadcast (bool temporary) DEBUG_V3:Function started")); + #endif + if(!temporary) + broadcast_enabled = false; + if(!broadcast_enabled) + writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_BCEN); +} + +void Enc28J60Network::enableMulticast (void) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::enableMulticast (void) DEBUG_V3:Function started")); + #endif + writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_MCEN); +} + +void Enc28J60Network::disableMulticast (void) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::disableMulticast (void) DEBUG_V3:Function started")); + #endif + writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_MCEN); +} + +uint8_t Enc28J60Network::readRegByte (uint8_t address) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::readRegByte (uint8_t address) DEBUG_V3:Function started")); + #endif + setBank(address); + return readOp(ENC28J60_READ_CTRL_REG, address); +} + +void Enc28J60Network::writeRegByte (uint8_t address, uint8_t data) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::writeRegByte (uint8_t address, uint8_t data) DEBUG_V3:Function started")); + #endif + setBank(address); + writeOp(ENC28J60_WRITE_CTRL_REG, address, data); +} + + +uint8_t Enc28J60Network::readByte(uint16_t addr) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::readByte(uint16_t addr) DEBUG_V3:Function started")); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + writeRegPair(ERDPTL, addr); + + CSACTIVE; + #if ENC28J60_USE_SPILIB + // issue read command + #if defined(ARDUINO) + SPI.transfer(ENC28J60_READ_BUF_MEM); + // read data + uint8_t c = SPI.transfer(0x00); + #endif + #if defined(__MBED__) + _spi.write(ENC28J60_READ_BUF_MEM); + // read data + uint8_t c = _spi.write(0x00); + #endif + CSPASSIVE; + return (c); + #else + // issue read command + SPDR = ENC28J60_READ_BUF_MEM; + waitspi(); + // read data + SPDR = 0x00; + waitspi(); + CSPASSIVE; + return (SPDR); + #endif +} + +void Enc28J60Network::writeByte(uint16_t addr, uint8_t data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::writeByte(uint16_t addr, uint8_t data) DEBUG_V3:Function started")); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + writeRegPair(EWRPTL, addr); + + CSACTIVE; + #if ENC28J60_USE_SPILIB + // issue write command + #if defined(ARDUINO) + SPI.transfer(ENC28J60_WRITE_BUF_MEM); + // write data + SPI.transfer(data); + #endif + #if defined(__MBED__) + _spi.write(ENC28J60_WRITE_BUF_MEM); + // write data + _spi.write(data); + #endif + #else + // issue write command + SPDR = ENC28J60_WRITE_BUF_MEM; + waitspi(); + // write data + SPDR = data; + waitspi(); + #endif + CSPASSIVE; +} + +void +Enc28J60Network::copyPacket(memhandle dest_pkt, memaddress dest_pos, memhandle src_pkt, memaddress src_pos, uint16_t len) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::copyPacket(memhandle dest_pkt, memaddress dest_pos, memhandle src_pkt, memaddress src_pos, uint16_t len) DEBUG_V3:Function started")); + #endif + memblock *dest = &blocks[dest_pkt]; + memblock *src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt]; + memaddress start = src_pkt == UIP_RECEIVEBUFFERHANDLE && src->begin + src_pos > RXSTOP_INIT ? src->begin + src_pos-((RXSTOP_INIT + 1)-RXSTART_INIT) : src->begin + src_pos; + enc28J60_mempool_block_move_callback(dest->begin+dest_pos,start,len); + // setERXRDPT(); let it to freePacket after all packets are saved +} + +void +enc28J60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("enc28J60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len) DEBUG_V3:Function started")); + #endif +//void +//Enc28J60Network::memblock_mv_cb(uint16_t dest, uint16_t src, uint16_t len) +//{ + //as ENC28J60 DMA is unable to copy single bytes: + if (len == 1) + { + Enc28J60Network::writeByte(dest,Enc28J60Network::readByte(src)); + } + else + { + // calculate address of last byte + len += src - 1; + + /* 1. Appropriately program the EDMAST, EDMAND + and EDMADST register pairs. The EDMAST + registers should point to the first byte to copy + from, the EDMAND registers should point to the + last byte to copy and the EDMADST registers + should point to the first byte in the destination + range. The destination range will always be + linear, never wrapping at any values except from + 8191 to 0 (the 8-Kbyte memory boundary). + Extreme care should be taken when + programming the start and end pointers to + prevent a never ending DMA operation which + would overwrite the entire 8-Kbyte buffer. + */ + Enc28J60Network::writeRegPair(EDMASTL, src); + Enc28J60Network::writeRegPair(EDMADSTL, dest); + + if ((src <= RXSTOP_INIT)&& (len > RXSTOP_INIT))len -= ((RXSTOP_INIT + 1)-RXSTART_INIT); + Enc28J60Network::writeRegPair(EDMANDL, len); + + /* + 2. If an interrupt at the end of the copy process is + desired, set EIE.DMAIE and EIE.INTIE and + clear EIR.DMAIF. + + 3. Verify that ECON1.CSUMEN is clear. */ + Enc28J60Network::writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN); + + /* 4. Start the DMA copy by setting ECON1.DMAST. */ + Enc28J60Network::writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST); + + // wait until runnig DMA is completed + while (Enc28J60Network::readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST) + { + delay(1); + } + } +} + +void +Enc28J60Network::freePacket(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::freePacket(void) DEBUG_V3:Function started")); + #endif + setERXRDPT(); +} + +uint8_t +Enc28J60Network::readOp(uint8_t op, uint8_t address) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::readOp(uint8_t op, uint8_t address) DEBUG_V3:Function started")); + #endif + CSACTIVE; + // issue read command + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + SPI.transfer(op | (address & ADDR_MASK)); + // read data + if(address & 0x80) + { + // do dummy read if needed (for mac and mii, see datasheet page 29) + SPI.transfer(0x00); + } + uint8_t c = SPI.transfer(0x00); + #endif + #if defined(__MBED__) + _spi.write(op | (address & ADDR_MASK)); + // read data + if(address & 0x80) + { + // do dummy read if needed (for mac and mii, see datasheet page 29) + _spi.write(0x00); + } + uint8_t c = _spi.write(0x00); + #endif + // release CS + CSPASSIVE; + return(c); + #else + // issue read command + SPDR = op | (address & ADDR_MASK); + waitspi(); + // read data + SPDR = 0x00; + waitspi(); + // do dummy read if needed (for mac and mii, see datasheet page 29) + if(address & 0x80) + { + SPDR = 0x00; + waitspi(); + } + // release CS + CSPASSIVE; + return(SPDR); + #endif + #if defined(ESP8266) + yield(); + #endif +} + +void +Enc28J60Network::writeOp(uint8_t op, uint8_t address, uint8_t data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::writeOp(uint8_t op, uint8_t address, uint8_t data) DEBUG_V3:Function started")); + #endif + CSACTIVE; + // issue write command + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + SPI.transfer(op | (address & ADDR_MASK)); + // write data + SPI.transfer(data); + #endif + #if defined(__MBED__) + _spi.write(op | (address & ADDR_MASK)); + // write data + _spi.write(data); + #endif + #else + // issue write command + SPDR = op | (address & ADDR_MASK); + waitspi(); + // write data + SPDR = data; + waitspi(); + #endif + CSPASSIVE; + #if defined(ESP8266) + yield(); + #endif +} + +void +Enc28J60Network::readBuffer(uint16_t len, uint8_t* data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::readBuffer(uint16_t len, uint8_t* data) DEBUG_V3:Function started")); + #endif + CSACTIVE; + // issue read command + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + SPI.transfer(ENC28J60_READ_BUF_MEM); + #endif + #if defined(__MBED__) + _spi.write(ENC28J60_READ_BUF_MEM); + #endif + #else + SPDR = ENC28J60_READ_BUF_MEM; + waitspi(); + #endif + while(len) + { + len--; + // read data + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + *data = SPI.transfer(0x00); + #endif + #if defined(__MBED__) + *data = _spi.write(0x00); + #endif + #else + SPDR = 0x00; + waitspi(); + *data = SPDR; + #endif + data++; + } + //*data='\0'; + CSPASSIVE; +} + +void +Enc28J60Network::writeBuffer(uint16_t len, uint8_t* data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::writeBuffer(uint16_t len, uint8_t* data) DEBUG_V3:Function started")); + #endif + CSACTIVE; + // issue write command + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + SPI.transfer(ENC28J60_WRITE_BUF_MEM); + #endif + #if defined(__MBED__) + _spi.write(ENC28J60_WRITE_BUF_MEM); + #endif + #else + SPDR = ENC28J60_WRITE_BUF_MEM; + waitspi(); + #endif + while(len) + { + len--; + // write data + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + SPI.transfer(*data); + #endif + #if defined(__MBED__) + _spi.write(*data); + #endif + data++; + #else + SPDR = *data; + data++; + waitspi(); + #endif + } + CSPASSIVE; +} + +void +Enc28J60Network::setBank(uint8_t address) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::setBank(uint8_t address) DEBUG_V3:Function started")); + #endif + // set the bank (if needed) + if((address & BANK_MASK) != bank) + { + // set the bank + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0)); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5); + bank = (address & BANK_MASK); + } +} + +uint8_t +Enc28J60Network::readReg(uint8_t address) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::readReg(uint8_t address) DEBUG_V3:Function started")); + #endif + // set the bank + setBank(address); + // do the read + return readOp(ENC28J60_READ_CTRL_REG, address); +} + +void +Enc28J60Network::writeReg(uint8_t address, uint8_t data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::writeReg(uint8_t address, uint8_t data) DEBUG_V3:Function started")); + #endif + // set the bank + setBank(address); + // do the write + writeOp(ENC28J60_WRITE_CTRL_REG, address, data); +} + +void +Enc28J60Network::writeRegPair(uint8_t address, uint16_t data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::writeRegPair(uint8_t address, uint16_t data) DEBUG_V3:Function started")); + #endif + // set the bank + setBank(address); + // do the write + writeOp(ENC28J60_WRITE_CTRL_REG, address, (data&0xFF)); + writeOp(ENC28J60_WRITE_CTRL_REG, address+1, (data) >> 8); +} + +void +Enc28J60Network::phyWrite(uint8_t address, uint16_t data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::phyWrite(uint8_t address, uint16_t data) DEBUG_V3:Function started")); + #endif + unsigned int timeout = 15; + // set the PHY register address + writeReg(MIREGADR, address); + // write the PHY data + writeRegPair(MIWRL, data); + // wait until the PHY write completes + while (readReg(MISTAT) & MISTAT_BUSY) + { + delay(10); + #if defined(ESP8266) + wdt_reset(); + #endif + if (--timeout == 0) + { + #if ACTLOGLEVEL>=LOG_ERR + LogObject.uart_send_strln(F("Enc28J60Network::phyWrite ERROR:TIMEOUT !!")); + #endif + return; + } + } +} + +uint16_t +Enc28J60Network::phyRead(uint8_t address) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::phyRead(uint8_t address) DEBUG_V3:Function started")); + #endif + unsigned int timeout = 15; + writeReg(MIREGADR,address); + writeReg(MICMD, MICMD_MIIRD); + // wait until the PHY read completes + while(readReg(MISTAT) & MISTAT_BUSY) + { + delay(10); + #if defined(ESP8266) + wdt_reset(); + #endif + if (--timeout == 0) + { + #if ACTLOGLEVEL>=LOG_ERR + LogObject.uart_send_strln(F("Enc28J60Network::phyRead ERROR:TIMEOUT !!")); + #endif + return 0; + } + } + writeReg(MICMD, 0); + return (readReg(MIRDL) | readReg(MIRDH) << 8); +} + +void +Enc28J60Network::clkout(uint8_t clk) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::clkout(uint8_t clk) DEBUG_V3:Function started")); + #endif + //setup clkout: 2 is 12.5MHz: + writeReg(ECOCON, clk & 0x7); +} + +uint16_t +Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len) DEBUG_V3:Function started")); + #endif + uint16_t t; + len = setReadPtr(handle, pos, len)-1; + CSACTIVE; + // issue read command + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + SPI.transfer(ENC28J60_READ_BUF_MEM); + #endif + #if defined(__MBED__) + _spi.write(ENC28J60_READ_BUF_MEM); + #endif + #else + SPDR = ENC28J60_READ_BUF_MEM; + waitspi(); + #endif + uint16_t i; + for (i = 0; i < len; i+=2) + { + // read data + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + t = SPI.transfer(0x00) << 8; + t += SPI.transfer(0x00); + #endif + #if defined(__MBED__) + t = _spi.write(0x00) << 8; + t += _spi.write(0x00); + #endif + #else + SPDR = 0x00; + waitspi(); + t = SPDR << 8; + SPDR = 0x00; + waitspi(); + t += SPDR; + #endif + sum += t; + if(sum < t) + { + sum++; /* carry */ + } + } + if(i == len) + { + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + t = (SPI.transfer(0x00) << 8) + 0; + #endif + #if defined(__MBED__) + t = (_spi.write(0x00) << 8) + 0; + #endif + #else + SPDR = 0x00; + waitspi(); + t = (SPDR << 8) + 0; + #endif + sum += t; + if(sum < t) + { + sum++; /* carry */ + } + } + CSPASSIVE; + + /* Return sum in host byte order. */ + return sum; +} + +void +Enc28J60Network::powerOff(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::powerOff(void) DEBUG_V3:Function started")); + #endif + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN); + delay(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS); + delay(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV); +} + +void +Enc28J60Network::powerOn(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::powerOn(void) DEBUG_V3:Function started")); + #endif + writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV); + delay(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + delay(50); +} + +// read erevid from object: +uint8_t +Enc28J60Network::geterevid(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_str(F("Enc28J60Network::geterevid(void) DEBUG_V3:Function started and return:")); + LogObject.uart_send_decln(erevid); + #endif + return(erevid); +} + +// read the phstat2 of the chip: +uint16_t +Enc28J60Network::PhyStatus(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_str(F("Enc28J60Network::PhyStatus(void) DEBUG_V3:Function started")); + LogObject.uart_send_decln(erevid); + #endif + uint16_t phstat2; + phstat2=phyRead(PHSTAT2); + if ((phstat2 & 0x20) > 0) {phstat2=phstat2 &0x100;} + phstat2=(phstat2 & 0xFF00) | erevid; + if ((phstat2 & 0x8000) > 0) {phstat2=0;} + return phstat2; +} + +bool +Enc28J60Network::linkStatus(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::linkStatus(void) DEBUG_V3:Function started")); + #endif + return (phyRead(PHSTAT2) & 0x0400) > 0; +} diff --git a/LibraryPatches/UIPEthernet-2.0.9/utility/Enc28J60Network.h b/LibraryPatches/UIPEthernet-2.0.9/utility/Enc28J60Network.h new file mode 100644 index 0000000..5174462 --- /dev/null +++ b/LibraryPatches/UIPEthernet-2.0.9/utility/Enc28J60Network.h @@ -0,0 +1,337 @@ +/* + Enc28J60NetworkClass.h + UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. + + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + inspired by enc28j60.c file from the AVRlib library by Pascal Stang. + For AVRlib See http://www.procyonengineering.com/ + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef Enc28J60Network_H_ +#define Enc28J60Network_H_ + +// KH mod +#if defined(ESP32) + //pin SS already defined in ESP32 as pin 5, don't use this as conflict with SPIFFS, EEPROM, etc. + // Use in GPIO13 + #warning ENC28J60Network.h => use ESP32, change ENC28J60_CONTROL_CS/SS_PIN_DEFAULT to GPIO13, MOSI(23), MISO(19), SCK(18) + #define ENC28J60_CONTROL_CS 13 +#endif + +// KH, For nRF52 +#if ( defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || defined(NRF52840_CLUE) || \ + defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #include + #define ENC28J60_USE_SPILIB 1 + + #ifndef USE_THIS_SS_PIN + // default to pin 10 + #define ENC28J60_CONTROL_CS 10 + #else + #warning Using USE_THIS_SS_PIN in Enc28J60Network.h for nRF52 + #define ENC28J60_CONTROL_CS USE_THIS_SS_PIN + #endif +#endif + +// KH, For SAMD21/SAMD51 +#if ( defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) \ + || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_SAMD_MKRFox1200) || defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) \ + || defined(ARDUINO_SAMD_MKRGSM1400) || defined(ARDUINO_SAMD_MKRNB1500) || defined(ARDUINO_SAMD_MKRVIDOR4000) || defined(__SAMD21G18A__) \ + || defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(__SAMD21E18A__) || defined(__SAMD51__) || defined(__SAMD51J20A__) || defined(__SAMD51J19A__) \ + || defined(__SAMD51G19A__) || defined(__SAMD51P19A__) || defined(__SAMD21G18A__) ) + #include + #define ENC28J60_USE_SPILIB 1 + + #ifndef USE_THIS_SS_PIN + // default to pin 10 + #define ENC28J60_CONTROL_CS 10 + #else + #warning Using USE_THIS_SS_PIN in Enc28J60Network.h for SAMD + #define ENC28J60_CONTROL_CS USE_THIS_SS_PIN + #endif +#endif +////// + +#include "mempool.h" +#if defined(__MBED__) + #include + //UIPEthernet(SPI_MOSI, SPI_MISO, SPI_SCK, SPI_CS); + #if defined(TARGET_LPC1768) + #define SPI_MOSI p11 + #define SPI_MISO p12 + #define SPI_SCK p13 + #define SPI_CS p8 + #elif defined(TARGET_LPC1114) + #define SPI_MOSI dp2 + #define SPI_MISO dp1 + #define SPI_SCK dp6 + #define SPI_CS dp25 + #elif defined(TARGET_LPC11U68) + #define SPI_MOSI P0_9 + #define SPI_MISO P0_8 + #define SPI_SCK P1_29 + #define SPI_CS P0_2 + #elif defined(TARGET_NUCLEO_F103RB) || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_F030R8) \ + || defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F302R8) || defined(TARGET_NUCLEO_L053R8) \ + || defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F334R8) || defined(TARGET_NUCLEO_F072RB) \ + || defined(TARGET_NUCLEO_F091RC) || defined(TARGET_NUCLEO_F303RE) || defined(TARGET_NUCLEO_F070RB) + #define SPI_MOSI D4 + #define SPI_MISO D5 + #define SPI_SCK D3 + #define SPI_CS D2 + #endif + #define ENC28J60_CONTROL_CS SPI_CS +#endif + +#if defined(STM32F3) || defined(STM32F2) //This is workaround for stm32duino STM32F2, and adafruit wiced feather STM32F2 + #define BOARD_SPI1_NSS_PIN PA4 + #define BOARD_SPI1_SCK_PIN PA5 + #define BOARD_SPI1_MISO_PIN PA6 + #define BOARD_SPI1_MOSI_PIN PA7 +#endif //This is workaround for stm32duino STM32F3, and adafruit wiced feather STM32F2 + +#if defined(BOARD_discovery_f4) + #define __STM32F4__ +#endif +#if defined(__MK20DX128__) || defined(__MKL26Z64__) + #include +#endif + +#if !defined(ENC28J60_CONTROL_CS) + #if defined(__AVR__) || defined(ESP8266) || defined(__RFduino__) + // Arduino Uno (__AVR__) SS defined to pin 10 + // Arduino Leonardo (ARDUINO_AVR_LEONARDO) SS defined to LED_BUILTIN_RX (17) + // Arduino Mega(__AVR_ATmega2560__) SS defined to pin 53 + // ESP8266 (ESP8266) SS defined to pin 15 + #if defined(ARDUINO_AVR_LEONARDO) || defined(ARDUINO_AVR_MICRO) + #define ENC28J60_CONTROL_CS PIN_A10 + #warning "Using LEONARDO borad PIN_A10 for ENC28J60_CONTROL_CS. Use UIPEthernet::init(uint8_t) to change it." + #else + #define ENC28J60_CONTROL_CS SS + #endif + #elif defined(ARDUINO_ARCH_AMEBA) //Defined SS to pin 10 + #define ENC28J60_CONTROL_CS SS //PC_0 A5 10 + #elif defined(ARDUINO_ARCH_SAM) + // Arduino Due (ARDUINO_ARCH_SAM) BOARD_SPI_DEFAULT_SS (SS3) defined to pin 78 + //#define ENC28J60_CONTROL_CS BOARD_SPI_DEFAULT_SS + #define ENC28J60_CONTROL_CS BOARD_SPI_SS0 + #elif defined(ARDUINO_ARCH_SAMD) + #define ENC28J60_CONTROL_CS SS + #elif defined(__ARDUINO_ARC__) //Intel ARC32 Genuino 101 + #define ENC28J60_CONTROL_CS SS + #elif defined(__RFduino__) //RFduino + #define ENC28J60_CONTROL_CS SS + #elif defined(ARDUINO_ARCH_STM32) // STM32duino core + #define ENC28J60_CONTROL_CS SS + #elif defined(ARDUINO_ARCH_ESP32) // arduino-esp32 + #define ENC28J60_CONTROL_CS SS + #elif defined(STM32_MCU_SERIES) || defined(__STM32F1__) || defined(__STM32F3__) || defined(STM32F3) || defined(__STM32F4__) || defined(STM32F2) + #if defined(BOARD_SPI1_NSS_PIN) + #define ENC28J60_CONTROL_CS BOARD_SPI1_NSS_PIN + #elif defined(ARDUINO_STM32F4_NETDUINO2PLUS) + #define ENC28J60_CONTROL_CS PC8 + #else + #define ENC28J60_CONTROL_CS SPI.nssPin() + //#define ENC28J60_CONTROL_CS PA4 + #endif + #elif defined(__MK20DX128__) || defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) + #define ENC28J60_CONTROL_CS PIN_SPI_SS + #endif +#endif +#if !defined(ENC28J60_CONTROL_CS) + #warning "Default ENC28J60_CONTROL_CS could not be defined! Use UIPEthernet::init(uint8_t) to set it." + #define ENC28J60_CONTROL_CS 0 +#endif + +extern uint8_t ENC28J60ControlCS; + +#if !defined(SPI_MOSI) + #if defined(__AVR__) || defined(ESP8266) || defined(__RFduino__) + #define SPI_MOSI MOSI + #elif defined(ARDUINO_ARCH_AMEBA) + #define SPI_MOSI 11 //PC_2 + #elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) + #define SPI_MOSI PIN_SPI_MOSI + #elif defined(__ARDUINO_ARC__) //Intel ARC32 Genuino 101 + #define SPI_MOSI MOSI + #elif defined(__RFduino__) //RFduino + #define SPI_MOSI MOSI + #elif defined(ARDUINO_ARCH_STM32) // STM32duino core + #define SPI_MOSI MOSI + #elif defined(ARDUINO_ARCH_ESP32) // arduino-esp32 + #define SPI_MOSI MOSI + #elif defined(STM32_MCU_SERIES) || defined(__STM32F1__) || defined(__STM32F3__) || defined(STM32F3) || defined(__STM32F4__) || defined(STM32F2) + #if defined(BOARD_SPI1_MOSI_PIN) + #define SPI_MOSI BOARD_SPI1_MOSI_PIN + #else + #define SPI_MOSI SPI.mosiPin() + #endif + #elif defined(__MK20DX128__) || defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) + #define SPI_MOSI PIN_SPI_MOSI + #endif +#endif +#if !defined(SPI_MOSI) + // KH mod + //#error "Not defined SPI_MOSI!" + #define SPI_MOSI MOSI + ////// +#endif + +#if !defined(SPI_MISO) + #if defined(__AVR__) || defined(ESP8266) || defined(__RFduino__) + #define SPI_MISO MISO + #elif defined(ARDUINO_ARCH_AMEBA) + #define SPI_MISO 12 //PC_3 + #elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) + #define SPI_MISO PIN_SPI_MISO + #elif defined(__ARDUINO_ARC__) //Intel ARC32 Genuino 101 + #define SPI_MISO MISO + #elif defined(__RFduino__) //RFduino + #define SPI_MISO MISO + #elif defined(ARDUINO_ARCH_STM32) // STM32duino core + #define SPI_MISO MISO + #elif defined(ARDUINO_ARCH_ESP32) // arduino-esp32 + #define SPI_MISO MISO + #elif defined(STM32_MCU_SERIES) || defined(__STM32F1__) || defined(__STM32F3__) || defined(STM32F3) || defined(__STM32F4__) || defined(STM32F2) + #if defined(BOARD_SPI1_MISO_PIN) + #define SPI_MISO BOARD_SPI1_MISO_PIN + #else + #define SPI_MISO SPI.misoPin() + #endif + #elif defined(__MK20DX128__) || defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) + #define SPI_MISO PIN_SPI_MISO + #endif +#endif +#if !defined(SPI_MISO) + // KH mod + //#error "Not defined SPI_MISO!" + #define SPI_MISO MISO + ////// +#endif +#if !defined(SPI_SCK) + #if defined(__AVR__) || defined(ESP8266) || defined(__RFduino__) + #define SPI_SCK SCK + #elif defined(ARDUINO_ARCH_AMEBA) + #define SPI_SCK 13 //PC_1 A4 + #elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) + #define SPI_SCK PIN_SPI_SCK + #elif defined(__ARDUINO_ARC__) //Intel ARC32 Genuino 101 + #define SPI_SCK SCK + #elif defined(__RFduino__) //RFduino + #define SPI_SCK SCK + #elif defined(ARDUINO_ARCH_STM32) // STM32duino core + #define SPI_SCK SCK + #elif defined(ARDUINO_ARCH_ESP32) // arduino-esp32 + #define SPI_SCK SCK + #elif defined(STM32_MCU_SERIES) || defined(__STM32F1__) || defined(__STM32F3__) || defined(STM32F3) || defined(__STM32F4__) || defined(STM32F2) + #if defined(BOARD_SPI1_SCK_PIN) + #define SPI_SCK BOARD_SPI1_SCK_PIN + #else + #define SPI_SCK SPI.sckPin() + #endif + #elif defined(__MK20DX128__) || defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) + #define SPI_SCK PIN_SPI_SCK + #endif +#endif +#if !defined(SPI_SCK) + // KH, For nRF52 + //#error "Not defined SPI_SCK!" + #define SPI_SCK SCK + ////// +#endif + +#if defined(__MBED__) || defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) || defined(__ARDUINO_ARC__) || defined(__STM32F1__) || defined(__STM32F3__) || defined(STM32F3) || defined(__STM32F4__) || defined(STM32F2) || defined(ESP8266) || defined(ARDUINO_ARCH_AMEBA) || defined(__MK20DX128__) || defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) || defined(__RFduino__) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) + #if defined(ARDUINO) && (!defined(ARDUINO_ARCH_STM32) && defined(STM32F3)) + #include "HardwareSPI.h" + #else + #include + #endif + #define ENC28J60_USE_SPILIB 1 +#endif + +#define UIP_RECEIVEBUFFERHANDLE 0xff + +#define UIP_SENDBUFFER_PADDING 7 +#define UIP_SENDBUFFER_OFFSET 1 + +/* + * Empfangen von ip-header, arp etc... + * wenn tcp/udp -> tcp/udp-callback -> assign new packet to connection + */ + +#define TX_COLLISION_RETRY_COUNT 10 + +class Enc28J60Network : public MemoryPool +{ + +private: + static uint16_t nextPacketPtr; + static uint8_t bank; + static uint8_t erevid; + + static struct memblock receivePkt; + + static bool broadcast_enabled; //!< True if broadcasts enabled (used to allow temporary disable of broadcast for DHCP or other internal functions) + + static uint8_t readOp(uint8_t op, uint8_t address); + static void writeOp(uint8_t op, uint8_t address, uint8_t data); + static uint16_t setReadPtr(memhandle handle, memaddress position, uint16_t len); + static void setERXRDPT(void); + static void readBuffer(uint16_t len, uint8_t* data); + static void writeBuffer(uint16_t len, uint8_t* data); + static uint8_t readByte(uint16_t addr); + static void writeByte(uint16_t addr, uint8_t data); + static void setBank(uint8_t address); + static uint8_t readReg(uint8_t address); + static void writeReg(uint8_t address, uint8_t data); + static void writeRegPair(uint8_t address, uint16_t data); + static void phyWrite(uint8_t address, uint16_t data); + static uint16_t phyRead(uint8_t address); + static void clkout(uint8_t clk); + + static void enableBroadcast (bool temporary); + static void disableBroadcast (bool temporary); + static void enableMulticast (void); + static void disableMulticast (void); + + static uint8_t readRegByte (uint8_t address); + static void writeRegByte (uint8_t address, uint8_t data); + + friend void enc28J60_mempool_block_move_callback(memaddress,memaddress,memaddress); + +public: + + void powerOn(void); + void powerOff(void); + static uint8_t geterevid(void); + uint16_t PhyStatus(void); + static bool linkStatus(void); + + static void init(uint8_t* macaddr); + static memhandle receivePacket(void); + static void freePacket(void); + static memaddress blockSize(memhandle handle); + static bool sendPacket(memhandle handle); + static uint16_t readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); + static uint16_t writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); + static void copyPacket(memhandle dest, memaddress dest_pos, memhandle src, memaddress src_pos, uint16_t len); + static uint16_t chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len); +}; + +#endif /* Enc28J60NetworkClass_H_ */ diff --git a/LibraryPatches/UIPEthernet/UIPEthernet.cpp b/LibraryPatches/UIPEthernet/UIPEthernet.cpp new file mode 100644 index 0000000..df35732 --- /dev/null +++ b/LibraryPatches/UIPEthernet/UIPEthernet.cpp @@ -0,0 +1,641 @@ +/* + UIPEthernet.cpp - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#if defined(ARDUINO) + #include +#endif +#if defined(__MBED__) + #include + #include "mbed/millis.h" +#endif +#include "UIPEthernet.h" +#include "utility/logging.h" +#include "utility/Enc28J60Network.h" + +#include "UIPUdp.h" + +extern "C" +{ +#include "utility/uipopt.h" +#include "utility/uip.h" +#include "utility/uip_arp.h" +#include "utility/uip_timer.h" +} + +#define ETH_HDR ((struct uip_eth_hdr *)&uip_buf[0]) + +memhandle UIPEthernetClass::in_packet(NOBLOCK); +memhandle UIPEthernetClass::uip_packet(NOBLOCK); +uint8_t UIPEthernetClass::uip_hdrlen(0); +uint8_t UIPEthernetClass::packetstate(0); + +unsigned long UIPEthernetClass::periodic_timer; + +IPAddress UIPEthernetClass::_dnsServerAddress; +#if UIP_UDP + DhcpClass* UIPEthernetClass::_dhcp(NULL); + static DhcpClass s_dhcp; // Placing this instance here is saving 40K to final *.bin (see bug below) +#endif + +// Because uIP isn't encapsulated within a class we have to use global +// variables, so we can only have one TCP/IP stack per program. + +UIPEthernetClass::UIPEthernetClass() +{ +} + +void UIPEthernetClass::init(const uint8_t pin) +{ + ENC28J60ControlCS = pin; +} + +#if UIP_UDP +int +UIPEthernetClass::begin(const uint8_t* mac) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var _mac_address + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac, sizeof(_mac_address)); + ////// + + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac) DEBUG_V3:Function started")); + #endif + //static DhcpClass s_dhcp; // <-- this is a bug ! + // I leave it there commented for history. It is bring all GCC "new" memory allocation code, making the *.bin almost 40K bigger. I've move it globally. + _dhcp = &s_dhcp; + // Initialise the basic info + netInit(mac); + + // Now try to get our config info from a DHCP server + int ret = _dhcp->beginWithDHCP((uint8_t*)mac); + if(ret == 1) + { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + configure(_dhcp->getLocalIp(),_dhcp->getDnsServerIp(),_dhcp->getGatewayIp(),_dhcp->getSubnetMask()); + } + return ret; +} +#endif + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var _mac_address + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac, sizeof(_mac_address)); + ////// + + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip) DEBUG_V3:Function started")); + #endif + IPAddress dns = ip; + dns[3] = 1; + begin(mac, ip, dns); +} + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var _mac_address + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac, sizeof(_mac_address)); + ////// + + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns) DEBUG_V3:Function started")); + #endif + IPAddress gateway = ip; + gateway[3] = 1; + begin(mac, ip, dns, gateway); +} + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var _mac_address + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac, sizeof(_mac_address)); + ////// + + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway) DEBUG_V3:Function started")); + #endif + IPAddress subnet(255, 255, 255, 0); + begin(mac, ip, dns, gateway, subnet); +} + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) +{ + // KH mod to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + // Now store to private var _mac_address + //uint8_t _mac_address[6] ={0,}; + memcpy(_mac_address, mac, sizeof(_mac_address)); + ////// + + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) DEBUG_V3:Function started")); + #endif + netInit(mac); + configure(ip,dns,gateway,subnet); +} + +int UIPEthernetClass::maintain(){ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::maintain() DEBUG_V3:Function started")); + #endif + tick(); + int rc = DHCP_CHECK_NONE; +#if UIP_UDP + if(_dhcp != NULL){ + //we have a pointer to dhcp, use it + rc = _dhcp->checkLease(); + switch ( rc ){ + case DHCP_CHECK_NONE: + //nothing done + break; + case DHCP_CHECK_RENEW_OK: + case DHCP_CHECK_REBIND_OK: + //we might have got a new IP. + configure(_dhcp->getLocalIp(),_dhcp->getDnsServerIp(),_dhcp->getGatewayIp(),_dhcp->getSubnetMask()); + break; + default: + //this is actually a error, it will retry though + break; + } + } + return rc; +#endif +} + +EthernetLinkStatus UIPEthernetClass::linkStatus() +{ + if (!Enc28J60.geterevid()) + return Unknown; + return Enc28J60.linkStatus() ? LinkON : LinkOFF; +} + +IPAddress UIPEthernetClass::localIP() +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::localIP() DEBUG_V3:Function started")); + #endif + IPAddress ret; + uip_ipaddr_t a; + uip_gethostaddr(a); + return ip_addr_uip(a); +} + +IPAddress UIPEthernetClass::subnetMask() +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::subnetMask() DEBUG_V3:Function started")); + #endif + IPAddress ret; + uip_ipaddr_t a; + uip_getnetmask(a); + return ip_addr_uip(a); +} + +IPAddress UIPEthernetClass::gatewayIP() +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::gatewayIP() DEBUG_V3:Function started")); + #endif + IPAddress ret; + uip_ipaddr_t a; + uip_getdraddr(a); + return ip_addr_uip(a); +} + +IPAddress UIPEthernetClass::dnsServerIP() +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::dnsServerIP() DEBUG_V3:Function started")); + #endif + return _dnsServerAddress; +} + +void +UIPEthernetClass::tick() +{ +#if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::tick() DEBUG_V3:Function started")); +#endif +if (Enc28J60Network::geterevid()==0) + { + #if ACTLOGLEVEL>=LOG_ERR + LogObject.uart_send_strln(F("UIPEthernetClass::tick() ERROR:EREVID=0 -> Not found ENC28j60 device !! Function ended !!")); + #endif + return; + } +#if defined(ESP8266) + wdt_reset(); +#endif + if (in_packet == NOBLOCK) + { + in_packet = Enc28J60Network::receivePacket(); + #if ACTLOGLEVEL>=LOG_DEBUG + if (in_packet != NOBLOCK) + { + LogObject.uart_send_str(F("UIPEthernetClass::tick() DEBUG:receivePacket: ")); + LogObject.uart_send_decln(in_packet); + } + #endif + } + if (in_packet != NOBLOCK) + { + packetstate = UIPETHERNET_FREEPACKET; + uip_len = Enc28J60Network::blockSize(in_packet); + if (uip_len > 0) + { + Enc28J60Network::readPacket(in_packet,0,(uint8_t*)uip_buf,UIP_BUFSIZE); + if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_IP)) + { + uip_packet = in_packet; //required for upper_layer_checksum of in_packet! + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("UIPEthernetClass::tick() DEBUG:readPacket type IP, uip_len: ")); + LogObject.uart_send_decln(uip_len); + #endif + uip_arp_ipin(); + uip_input(); + if (uip_len > 0) + { + uip_arp_out(); + network_send(); + } + } + else if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_ARP)) + { + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("UIPEthernetClass::tick() DEBUG:readPacket type ARP, uip_len: ")); + LogObject.uart_send_decln(uip_len); + #endif + uip_arp_arpin(); + if (uip_len > 0) + { + network_send(); + } + } + } + if (in_packet != NOBLOCK && (packetstate & UIPETHERNET_FREEPACKET)) + { + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("UIPEthernetClass::tick() DEBUG:freeing packet: ")); + LogObject.uart_send_decln(in_packet); + #endif + Enc28J60Network::freePacket(); + in_packet = NOBLOCK; + } + } + + unsigned long now = millis(); + +#if UIP_CLIENT_TIMER >= 0 + bool periodic = (long)( now - periodic_timer ) >= 0; + for (int i = 0; i < UIP_CONNS; i++) + { +#else + if ((long)( now - periodic_timer ) >= 0) + { + periodic_timer = now + UIP_PERIODIC_TIMER; + + for (int i = 0; i < UIP_CONNS; i++) + { +#endif + + uip_conn = &uip_conns[i]; + +#if UIP_CLIENT_TIMER >= 0 + if (periodic) + { +#endif + + uip_process(UIP_TIMER); + +#if UIP_CLIENT_TIMER >= 0 + } + else + { + if (uip_conn!=NULL) + { + if (((uip_userdata_t*)uip_conn->appstate)!=NULL) + { + if ((long)( now - ((uip_userdata_t*)uip_conn->appstate)->timer) >= 0) + { + uip_process(UIP_POLL_REQUEST); + } + else + { + continue; + } + } + else + { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::tick() DEBUG_V3:((uip_userdata_t*)uip_conn->appstate) is NULL")); + #endif + if ((long)( now - ((uip_userdata_t*)uip_conn)->timer) >= 0) + { + uip_process(UIP_POLL_REQUEST); + } + else + { + continue; + } + } + } + else + { + #if ACTLOGLEVEL>=LOG_ERR + LogObject.uart_send_strln(F("UIPEthernetClass::tick() ERROR:uip_conn is NULL")); + #endif + continue; + } + } +#endif + // If the above function invocation resulted in data that + // should be sent out on the Enc28J60Network, the global variable + // uip_len is set to a value > 0. + if (uip_len > 0) + { + uip_arp_out(); + network_send(); + } + } +#if UIP_CLIENT_TIMER >= 0 + if (periodic) + { + periodic_timer = now + UIP_PERIODIC_TIMER; +#endif +#if UIP_UDP + for (int i = 0; i < UIP_UDP_CONNS; i++) + { + uip_udp_periodic(i); + // If the above function invocation resulted in data that + // should be sent out on the Enc28J60Network, the global variable + // uip_len is set to a value > 0. */ + if (uip_len > 0) + { + UIPUDP::_send((uip_udp_userdata_t *)(uip_udp_conns[i].appstate)); + } + } +#endif /* UIP_UDP */ + } +} + +bool UIPEthernetClass::network_send() +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::network_send() DEBUG_V3:Function started")); + #endif + if (packetstate & UIPETHERNET_SENDPACKET) + { +#if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("UIPEthernetClass::network_send() DEBUG:uip_packet: ")); + LogObject.uart_send_dec(uip_packet); + LogObject.uart_send_str(F(", hdrlen: ")); + LogObject.uart_send_decln(uip_hdrlen); +#endif + Enc28J60Network::writePacket(uip_packet,0,uip_buf,uip_hdrlen); + packetstate &= ~ UIPETHERNET_SENDPACKET; + goto sendandfree; + } + uip_packet = Enc28J60Network::allocBlock(uip_len); + if (uip_packet != NOBLOCK) + { +#if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("UIPEthernetClass::network_send() DEBUG:uip_buf (uip_len): ")); + LogObject.uart_send_dec(uip_len); + LogObject.uart_send_str(F(", packet: ")); + LogObject.uart_send_decln(uip_packet); +#endif + Enc28J60Network::writePacket(uip_packet,0,uip_buf,uip_len); + goto sendandfree; + } + return false; +sendandfree: + Enc28J60Network::sendPacket(uip_packet); + Enc28J60Network::freeBlock(uip_packet); + uip_packet = NOBLOCK; + return true; +} + +void UIPEthernetClass::netInit(const uint8_t* mac) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::netInit(const uint8_t* mac) DEBUG_V3:Function started")); + #endif + periodic_timer = millis() + UIP_PERIODIC_TIMER; + + Enc28J60Network::init((uint8_t*)mac); + uip_seteth_addr(mac); + + uip_init(); + uip_arp_init(); +} + +void UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) DEBUG_V3:Function started")); + #endif + uip_ipaddr_t ipaddr; + + uip_ip_addr(ipaddr, ip); + uip_sethostaddr(ipaddr); + + uip_ip_addr(ipaddr, gateway); + uip_setdraddr(ipaddr); + + uip_ip_addr(ipaddr, subnet); + uip_setnetmask(ipaddr); + + _dnsServerAddress = dns; +} + +UIPEthernetClass UIPEthernet; + +/*---------------------------------------------------------------------------*/ +uint16_t +UIPEthernetClass::chksum(uint16_t sum, const uint8_t *data, uint16_t len) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::chksum(uint16_t sum, const uint8_t *data, uint16_t len) DEBUG_V3:Function started")); + #endif + uint16_t t; + const uint8_t *dataptr; + const uint8_t *last_byte; + + dataptr = data; + last_byte = data + len - 1; + + while(dataptr < last_byte) { /* At least two more bytes */ + t = (dataptr[0] << 8) + dataptr[1]; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + dataptr += 2; + } + + if(dataptr == last_byte) { + t = (dataptr[0] << 8) + 0; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + } + + /* Return sum in host byte order. */ + return sum; +} + +/*---------------------------------------------------------------------------*/ + +uint16_t +UIPEthernetClass::ipchksum(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("UIPEthernetClass::ipchksum(void) DEBUG_V3:Function started")); + #endif + uint16_t sum; + + sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); + return (sum == 0) ? 0xffff : htons(sum); +} + +/*---------------------------------------------------------------------------*/ +uint16_t +#if UIP_UDP +UIPEthernetClass::upper_layer_chksum(uint8_t proto) +#else +uip_tcpchksum(void) +#endif +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + #if UIP_UDP + LogObject.uart_send_strln(F("UIPEthernetClass::upper_layer_chksum(uint8_t proto) DEBUG_V3:Function started")); + #else + LogObject.uart_send_strln(F("uip_tcpchksum(void) INFO:Function started")); + #endif + #endif + uint16_t upper_layer_len; + uint16_t sum; + +#if UIP_CONF_IPV6 + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]); +#else /* UIP_CONF_IPV6 */ + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN; +#endif /* UIP_CONF_IPV6 */ + + /* First sum pseudoheader. */ + + /* IP protocol and length fields. This addition cannot carry. */ +#if UIP_UDP + sum = upper_layer_len + proto; +#else + sum = upper_layer_len + UIP_PROTO_TCP; +#endif + /* Sum IP source and destination addresses. */ + sum = UIPEthernetClass::chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); + + uint8_t upper_layer_memlen; +#if UIP_UDP + switch(proto) + { +// case UIP_PROTO_ICMP: +// case UIP_PROTO_ICMP6: +// upper_layer_memlen = upper_layer_len; +// break; + case UIP_PROTO_UDP: + upper_layer_memlen = UIP_UDPH_LEN; + break; + default: +// case UIP_PROTO_TCP: +#endif + upper_layer_memlen = (BUF->tcpoffset >> 4) << 2; +#if UIP_UDP + break; + } +#endif + sum = UIPEthernetClass::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen); +#if ACTLOGLEVEL>=LOG_DEBUG + #if UIP_UDP + LogObject.uart_send_str(F("UIPEthernetClass::upper_layer_chksum(uint8_t proto) DEBUG:uip_buf[")); + #else + LogObject.uart_send_str(F("uip_tcpchksum(void) DEBUG:uip_buf[")); + #endif + LogObject.uart_send_dec(UIP_IPH_LEN + UIP_LLH_LEN); + LogObject.uart_send_str(F("-")); + LogObject.uart_send_dec(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); + LogObject.uart_send_str(F("]: ")); + LogObject.uart_send_hexln(htons(sum)); +#endif + if (upper_layer_memlen < upper_layer_len) + { + sum = Enc28J60Network::chksum( + sum, + UIPEthernetClass::uip_packet, + UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen, + upper_layer_len - upper_layer_memlen + ); +#if ACTLOGLEVEL>=LOG_DEBUG + #if UIP_UDP + LogObject.uart_send_str(F("UIPEthernetClass::upper_layer_chksum(uint8_t proto) DEBUG:uip_packet(")); + #else + LogObject.uart_send_str(F("uip_tcpchksum(void) DEBUG:uip_packet(")); + #endif + LogObject.uart_send_dec(UIPEthernetClass::uip_packet); + LogObject.uart_send_str(F(")[")); + LogObject.uart_send_dec(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); + LogObject.uart_send_str(F("-")); + LogObject.uart_send_dec(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_len); + LogObject.uart_send_str(F("]: ")); + LogObject.uart_send_hexln(htons(sum)); +#endif + } + return (sum == 0) ? 0xffff : htons(sum); +} + +uint16_t +uip_ipchksum(void) +{ + return UIPEthernet.ipchksum(); +} + +#if UIP_UDP +uint16_t +uip_tcpchksum(void) +{ + uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_TCP); + return sum; +} + +uint16_t +uip_udpchksum(void) +{ + uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_UDP); + return sum; +} +#endif diff --git a/LibraryPatches/UIPEthernet/UIPEthernet.h b/LibraryPatches/UIPEthernet/UIPEthernet.h new file mode 100644 index 0000000..d02e538 --- /dev/null +++ b/LibraryPatches/UIPEthernet/UIPEthernet.h @@ -0,0 +1,158 @@ +/* + UIPEthernet.h - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef UIPETHERNET_H +#define UIPETHERNET_H + +#include "ethernet_comp.h" +#if defined(__MBED__) + #include +#endif +#if defined(ARDUINO) + #include + #if defined(__STM32F3__) || defined(STM32F3) || defined(__RFduino__) + #include "mbed/IPAddress.h" + #else + #include "IPAddress.h" + #endif +#endif +#include "utility/Enc28J60Network.h" +#include "utility/uipopt.h" +#include "Dhcp.h" +#if UIP_UDP + #include "UIPUdp.h" +#endif +#include "UIPClient.h" +#include "UIPServer.h" + +extern "C" +{ +#include "utility/uip_timer.h" +#include "utility/uip.h" +} + +#define UIPETHERNET_FREEPACKET 1 +#define UIPETHERNET_SENDPACKET 2 +#define UIPETHERNET_BUFFERREAD 4 + +#define uip_ip_addr(addr, ip) do { \ + ((u16_t *)(addr))[0] = HTONS(((ip[0]) << 8) | (ip[1])); \ + ((u16_t *)(addr))[1] = HTONS(((ip[2]) << 8) | (ip[3])); \ + } while(0) + +#define ip_addr_uip(a) IPAddress(a[0] & 0xFF, a[0] >> 8 , a[1] & 0xFF, a[1] >> 8) //TODO this is not IPV6 capable + +#define uip_seteth_addr(eaddr) do {uip_ethaddr.addr[0] = eaddr[0]; \ + uip_ethaddr.addr[1] = eaddr[1];\ + uip_ethaddr.addr[2] = eaddr[2];\ + uip_ethaddr.addr[3] = eaddr[3];\ + uip_ethaddr.addr[4] = eaddr[4];\ + uip_ethaddr.addr[5] = eaddr[5];} while(0) + +#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +enum EthernetLinkStatus { + Unknown, + LinkON, + LinkOFF +}; + +class UIPEthernetClass +{ +public: + UIPEthernetClass(); + + void init(const uint8_t pin); + + int begin(const uint8_t* mac); + void begin(const uint8_t* mac, IPAddress ip); + void begin(const uint8_t* mac, IPAddress ip, IPAddress dns); + void begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway); + void begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); + + // maintain() must be called at regular intervals to process the incoming serial + // data and issue IP events to the sketch. It does not return until all IP + // events have been processed. Renews dhcp-lease if required. + int maintain(); + + EthernetLinkStatus linkStatus(); + + // KH add to have similar function to Ethernet lib + // Certainly we can use void macAddress(uint8_t mac[]) to read from W5x00. + void MACAddress(uint8_t *mac_address) + { + memcpy(mac_address, _mac_address, sizeof(_mac_address)); + } + ////// + + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP(); + +private: + + // KH add to work with new func void MACAddress(uint8_t *mac_address); and SinricPro v2.5.1+ + uint8_t _mac_address[6] ={0,}; + ////// + + static memhandle in_packet; + static memhandle uip_packet; + static uint8_t uip_hdrlen; + static uint8_t packetstate; + + static IPAddress _dnsServerAddress; + #if UIP_UDP + static DhcpClass* _dhcp; + #endif + static unsigned long periodic_timer; + + static void netInit(const uint8_t* mac); + static void configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); + + static void tick(); + + static bool network_send(); + + friend class UIPServer; + + friend class UIPClient; + + friend class UIPUDP; + + static uint16_t chksum(uint16_t sum, const uint8_t* data, uint16_t len); + static uint16_t ipchksum(void); +#if UIP_UDP + static uint16_t upper_layer_chksum(uint8_t proto); +#endif + friend uint16_t uip_ipchksum(void); + friend uint16_t uip_tcpchksum(void); + friend uint16_t uip_udpchksum(void); + + friend void uipclient_appcall(void); + friend void uipudp_appcall(void); + +#if UIP_CONF_IPV6 + uint16_t uip_icmp6chksum(void); +#endif /* UIP_CONF_IPV6 */ +}; + +extern UIPEthernetClass UIPEthernet; + +#endif diff --git a/LibraryPatches/UIPEthernet/utility/Enc28J60Network.cpp b/LibraryPatches/UIPEthernet/utility/Enc28J60Network.cpp new file mode 100644 index 0000000..a280225 --- /dev/null +++ b/LibraryPatches/UIPEthernet/utility/Enc28J60Network.cpp @@ -0,0 +1,1244 @@ +/* + Enc28J60NetworkClass.h + UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. + + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + based on enc28j60.c file from the AVRlib library by Pascal Stang. + For AVRlib See http://www.procyonengineering.com/ + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + + +#include "Enc28J60Network.h" +#if defined(ARDUINO) + #include "Arduino.h" +#endif +#if defined(__MBED__) + #include + #include "mbed/millis.h" + #define delay(x) wait_ms(x) +#endif +#include "logging.h" + +// KH, For nRF52 +//#define ENC28J60_USE_SPILIB true + +uint8_t ENC28J60ControlCS = ENC28J60_CONTROL_CS; + +#if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + #if defined(STM32F2) + #include + #elif !defined(STM32F3) && !defined(__STM32F4__) + #include + extern SPIClass SPI; + //#elif defined(ARDUINO_ARCH_AMEBA) + //SPIClass SPI((void *)(&spi_obj), 11, 12, 13, 10); + //SPI _spi(SPI_MOSI,SPI_MISO,SPI_SCK,ENC28J60ControlCS); + #else + #include "HardwareSPI.h" + extern HardwareSPI SPI(1); + #endif + #endif + #if defined(__MBED__) + SPI _spi(SPI_MOSI,SPI_MISO,SPI_SCK); + DigitalOut _cs(ENC28J60ControlCS); + Serial LogObject(SERIAL_TX,SERIAL_RX); + #endif +#endif + +extern "C" { + #if defined(ARDUINO_ARCH_AVR) + // AVR-specific code + #include + #elif defined(ARDUINO_ARCH_SAM) + // SAM-specific code + #elif defined(ARDUINO_ARCH_SAMD) + // SAMD-specific code + #else + // generic, non-platform specific code + #endif +#include "enc28j60.h" +#include "uip.h" +} + +#if defined(ARDUINO) + // set CS to 0 = active + #define CSACTIVE digitalWrite(ENC28J60ControlCS, LOW) + // set CS to 1 = passive + #define CSPASSIVE digitalWrite(ENC28J60ControlCS, HIGH) +#endif +#if defined(__MBED__) + // set CS to 0 = active + #define CSACTIVE _cs=0 + // set CS to 1 = passive + #define CSPASSIVE _cs=1 +#endif + +// +#if defined(ARDUINO_ARCH_AVR) +#define waitspi() while(!(SPSR&(1<=LOG_DEBUG + LogObject.uart_send_str(F("ENC28J60::init DEBUG:csPin = ")); + LogObject.uart_send_decln(ENC28J60ControlCS); + LogObject.uart_send_str(F("ENC28J60::init DEBUG:miso = ")); + LogObject.uart_send_decln(SPI_MISO); + LogObject.uart_send_str(F("ENC28J60::init DEBUG:mosi = ")); + LogObject.uart_send_decln(SPI_MOSI); + LogObject.uart_send_str(F("ENC28J60::init DEBUG:sck = ")); + LogObject.uart_send_decln(SPI_SCK); + #endif +#if ENC28J60_USE_SPILIB + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_strln(F("ENC28J60::init DEBUG:Use SPI lib SPI.begin()")); + #endif + #if defined(ARDUINO) + #if defined(__STM32F3__) || defined(STM32F3) || defined(__STM32F4__) + SPI.begin(SPI_9MHZ, MSBFIRST, 0); + #else + SPI.begin(); + #endif + #endif + #if defined(ARDUINO_ARCH_AVR) + // AVR-specific code + SPI.setClockDivider(SPI_CLOCK_DIV2); //results in 8MHZ at 16MHZ system clock. + #elif defined(ARDUINO_ARCH_SAM) + // SAM-specific code + SPI.setClockDivider(10); //defaults to 21 which results in aprox. 4MHZ. A 10 should result in a little more than 8MHZ. + #elif defined(ARDUINO_ARCH_SAMD) + // SAMD-specific code + // Should we set clock divider? + SPI.setClockDivider(10); + #elif defined(__STM32F1__) || defined(__STM32F3__) + // generic, non-platform specific code + #define USE_STM32F1_DMAC 1 //on STM32 + // BOARD_NR_SPI >= 1 BOARD_SPI1_NSS_PIN, BOARD_SPI1_SCK_PIN, BOARD_SPI1_MISO_PIN, BOARD_SPI1_MOSI_PIN + SPI.setBitOrder(MSBFIRST); + SPI.setDataMode(SPI_MODE0); + SPI.setClockDivider(SPI_CLOCK_DIV8); //value 8 the result is 9MHz at 72MHz clock. + #else + #if defined(ARDUINO) + #if !defined(__STM32F3__) && !defined(STM32F3) && !defined(__STM32F4__) + SPI.setBitOrder(MSBFIRST); + #endif + //Settings for ESP8266 + //SPI.setDataMode(SPI_MODE0); + //SPI.setClockDivider(SPI_CLOCK_DIV16); + #endif + #if defined(__MBED__) + _spi.format(8, 0); // 8bit, mode 0 + _spi.frequency(7000000); // 7MHz + #endif + #endif +#else + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_strln(F("ENC28J60::init DEBUG:Use Native hardware SPI")); + #endif + pinMode(SPI_MOSI, OUTPUT); + pinMode(SPI_SCK, OUTPUT); + pinMode(SPI_MISO, INPUT); + //Hardware SS must be configured as OUTPUT to enable SPI-master (regardless of which pin is configured as ENC28J60ControlCS) + pinMode(SS, OUTPUT); + digitalWrite(SS,HIGH); + + digitalWrite(SPI_MOSI, LOW); + digitalWrite(SPI_SCK, LOW); + + // initialize SPI interface + // master mode and Fosc/2 clock: + SPCR = (1<=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:Before readOp(ENC28J60_READ_CTRL_REG, ESTAT)")); + #endif + nextPacketPtr = RXSTART_INIT; + while ((!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY) && (timeout>0)) + { + timeout=timeout-1; + delay(10); + #if defined(ESP8266) + wdt_reset(); + #endif + } + #if ACTLOGLEVEL>=LOG_ERR + if (timeout==0) {LogObject.uart_send_strln(F("ENC28J60::init ERROR:TIMEOUT !!"));} + #endif + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:After readOp(ENC28J60_READ_CTRL_REG, ESTAT)")); + #endif + // Rx start + writeRegPair(ERXSTL, RXSTART_INIT); + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:After writeRegPair(ERXSTL, RXSTART_INIT)")); + #endif + // set receive pointer address + writeRegPair(ERXRDPTL, RXSTART_INIT); + // RX end + writeRegPair(ERXNDL, RXSTOP_INIT); + // TX start + //writeRegPair(ETXSTL, TXSTART_INIT); + // TX end + //writeRegPair(ETXNDL, TXSTOP_INIT); + // do bank 1 stuff, packet filter: + // For broadcast packets we allow only ARP packtets + // All other packets should be unicast only for our mac (MAADR) + // + // The pattern to match on is therefore + // Type ETH.DST + // ARP BROADCAST + // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9 + // in binary these poitions are:11 0000 0011 1111 + // This is hex 303F->EPMM0=0x3f,EPMM1=0x30 + //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN! +// enableBroadcast(); // change to add ERXFCON_BCEN recommended by epam + writeReg(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN); + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:After writeReg(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN)")); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + writeRegPair(EPMM0, 0x303f); + writeRegPair(EPMCSL, 0xf7f9); + // + // + // do bank 2 stuff + // enable MAC receive + // and bring MAC out of reset (writes 0x00 to MACON2) + writeRegPair(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); + // enable automatic padding to 60bytes and CRC operations + writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:After writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN)")); + #endif + // set inter-frame gap (non-back-to-back) + writeRegPair(MAIPGL, 0x0C12); + // set inter-frame gap (back-to-back) + writeReg(MABBIPG, 0x12); + // Set the maximum packet size which the controller will accept + // Do not send packets longer than MAX_FRAMELEN: + writeRegPair(MAMXFLL, MAX_FRAMELEN); + // do bank 3 stuff + // write MAC address + // NOTE: MAC address in ENC28J60 is byte-backward + writeReg(MAADR5, macaddr[0]); + writeReg(MAADR4, macaddr[1]); + writeReg(MAADR3, macaddr[2]); + writeReg(MAADR2, macaddr[3]); + writeReg(MAADR1, macaddr[4]); + writeReg(MAADR0, macaddr[5]); + // no loopback of transmitted frames + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:Before phyWrite(PHCON2, PHCON2_HDLDIS)")); + #endif + phyWrite(PHCON2, PHCON2_HDLDIS); + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:After phyWrite(PHCON2, PHCON2_HDLDIS)")); + #endif + // switch to bank 0 + setBank(ECON1); + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:After setBank(ECON1)")); + #endif + // enable interrutps + writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE); + // enable packet reception + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + //Configure leds + phyWrite(PHLCON,0x476); + + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("ENC28J60::init DEBUG_V3:Before readReg(EREVID);")); + #endif + erevid=readReg(EREVID); + if (erevid==0xFF) {erevid=0;} + // microchip forgot to step the number on the silcon when they + // released the revision B7. 6 is now rev B7. We still have + // to see what they do when they release B8. At the moment + // there is no B8 out yet + //if (erevid > 5) ++erevid; + #if ACTLOGLEVEL>=LOG_INFO + LogObject.uart_send_str(F("ENC28J60::init INFO: Chip erevid=")); + LogObject.uart_send_dec(erevid); + LogObject.uart_send_strln(F(" initialization completed.")); + #endif + +// return Enc28J60Network::erevid; +} + +memhandle +Enc28J60Network::receivePacket(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::receivePacket(void) DEBUG_V3:Function started")); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + uint8_t rxstat; + uint16_t len; + // check if a packet has been received and buffered + //if( !(readReg(EIR) & EIR_PKTIF) ){ + // The above does not work. See Rev. B4 Silicon Errata point 6. + #if ACTLOGLEVEL>=LOG_ERR + if (erevid==0) + { + LogObject.uart_send_strln(F("Enc28J60Network::receivePacket(void) ERROR:ENC28j50 Device not found !! Bypass receivePacket function !!")); + } + #endif + uint8_t epktcnt=readReg(EPKTCNT); + if ((erevid!=0) && (epktcnt!=0)) + { + uint16_t readPtr = nextPacketPtr+6 > RXSTOP_INIT ? nextPacketPtr+6-RXSTOP_INIT+RXSTART_INIT : nextPacketPtr+6; + // Set the read pointer to the start of the received packet + writeRegPair(ERDPTL, nextPacketPtr); + // read the next packet pointer + nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0); + nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; + // read the packet length (see datasheet page 43) + len = readOp(ENC28J60_READ_BUF_MEM, 0); + len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; + len -= 4; //remove the CRC count + // read the receive status (see datasheet page 43) + rxstat = readOp(ENC28J60_READ_BUF_MEM, 0); + //rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("Enc28J60Network::receivePacket(void) DEBUG:receivePacket [")); + LogObject.uart_send_hex(readPtr); + LogObject.uart_send_str(F("-")); + LogObject.uart_send_hex((readPtr+len) % (RXSTOP_INIT+1)); + LogObject.uart_send_str(F("], next: ")); + LogObject.uart_send_hex(nextPacketPtr); + LogObject.uart_send_str(F(", stat: ")); + LogObject.uart_send_hex(rxstat); + LogObject.uart_send_str(F(", Packet count: ")); + LogObject.uart_send_dec(epktcnt); + LogObject.uart_send_str(F(" -> ")); + LogObject.uart_send_strln((rxstat & 0x80)!=0 ? "OK" : "failed"); + #endif + // decrement the packet counter indicate we are done with this packet + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); + // check CRC and symbol errors (see datasheet page 44, table 7-3): + // The ERXFCON.CRCEN is set by default. Normally we should not + // need to check this. + if (((rxstat & 0x80) != 0) && (nextPacketPtr<=RXSTOP_INIT)) + { + receivePkt.begin = readPtr; + receivePkt.size = len; + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("Enc28J60Network::receivePacket(void) DEBUG: rxstat OK. receivePkt.size=")); + LogObject.uart_send_decln(len); + #endif + return UIP_RECEIVEBUFFERHANDLE; + } + // Move the RX read pointer to the start of the next received packet + // This frees the memory we just read out + setERXRDPT(); + } + return (NOBLOCK); +} + +void +Enc28J60Network::setERXRDPT(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::setERXRDPT(void) DEBUG_V3:Function started")); + #endif + // Make sure the value is odd. See Rev. B1,B4,B5,B7 Silicon Errata issues 14 + uint16_t actnextPacketPtr = nextPacketPtr == RXSTART_INIT ? RXSTOP_INIT : nextPacketPtr-1; + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("Enc28J60Network::setERXRDPT(void) DEBUG:Set actnextPacketPtr:")); + LogObject.uart_send_hexln(actnextPacketPtr); + #endif + // datasheet: The ENC28J60 will always write up to, but not including + writeRegPair(ERXRDPTL, actnextPacketPtr); +} + +memaddress +Enc28J60Network::blockSize(memhandle handle) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::blockSize(memhandle handle) DEBUG_V3:Function started")); + #endif + return ((handle == NOBLOCK) || (erevid==0)) ? 0 : handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size; +} + +void +Enc28J60Network::sendPacket(memhandle handle) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::sendPacket(memhandle handle) INFO:Function started")); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + if (erevid==0) + { + #if ACTLOGLEVEL>=LOG_ERR + LogObject.uart_send_strln(F("Enc28J60Network::sendPacket(memhandle handle) ERROR:ENC28j50 Device not found !! Bypass sendPacket function !!")); + #endif + return; + } + + memblock *packet = &blocks[handle]; + uint16_t start = packet->begin-1; + uint16_t end = start + packet->size; + + // backup data at control-byte position + uint8_t data = readByte(start); + // write control-byte (if not 0 anyway) + if (data) + writeByte(start, 0); + + #if ACTLOGLEVEL>=LOG_DEBUG + LogObject.uart_send_str(F("Enc28J60Network::sendPacket(memhandle handle) DEBUG:sendPacket(")); + LogObject.uart_send_dec(handle); + LogObject.uart_send_str(F(") [")); + LogObject.uart_send_hex(start); + LogObject.uart_send_str(F("-")); + LogObject.uart_send_hex(end); + LogObject.uart_send_str(F("]: ")); + for (uint16_t i=start; i<=end; i++) + { + LogObject.uart_send_hex(readByte(i)); + LogObject.uart_send_str(F(" ")); + } + LogObject.uart_send_strln(F("")); + #endif + + // TX start + writeRegPair(ETXSTL, start); + // Set the TXND pointer to correspond to the packet size given + writeRegPair(ETXNDL, end); + // send the contents of the transmit buffer onto the network + + unsigned int retry = TX_COLLISION_RETRY_COUNT; + unsigned int timeout = 100; + do + { + // seydamir added + // Reset the transmit logic problem. See Rev. B7 Silicon Errata issues 12 and 13 + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST); + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST); + writeOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF | EIR_TXIF); + // end + + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); + // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. + //if( (readReg(EIR) & EIR_TXERIF) ) + // { + // writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS); + // } + + timeout = 100; + while (((readReg(EIR) & (EIR_TXIF | EIR_TXERIF)) == 0) && (timeout>0)) + { + timeout=timeout-1; + delay(10); + #if defined(ESP8266) + wdt_reset(); + #endif + } + if (timeout==0) + { + /* Transmit hardware probably hung, try again later. */ + /* Shouldn't happen according to errata 12 and 13. */ + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS); + #if ACTLOGLEVEL>=LOG_WARN + LogObject.uart_send_strln(F("Enc28J60Network::sendPacket(memhandle handle) WARNING:Collision")); + #endif + retry=retry-1; + } + } while ((timeout == 0) && (retry != 0)); + + //restore data on control-byte position + if (data) + writeByte(start, data); + + if (retry == 0) + { + #if ACTLOGLEVEL>=LOG_ERROR + LogObject.uart_send_strln(F("Enc28J60Network::sendPacket(memhandle handle) ERROR:COLLISION !!")); + #endif + return; + } +} + +uint16_t +Enc28J60Network::setReadPtr(memhandle handle, memaddress position, uint16_t len) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::setReadPtr(memhandle handle, memaddress position, uint16_t len) DEBUG_V3:Function started")); + #endif + memblock *packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle]; + memaddress start = handle == UIP_RECEIVEBUFFERHANDLE && packet->begin + position > RXSTOP_INIT ? packet->begin + position-RXSTOP_INIT+RXSTART_INIT : packet->begin + position; + + writeRegPair(ERDPTL, start); + + if (len > packet->size - position) + len = packet->size - position; + return len; +} + +uint16_t +Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) DEBUG_V3:Function started")); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + len = setReadPtr(handle, position, len); + readBuffer(len, buffer); + #if ACTLOGLEVEL>=LOG_DEBUG_V2 + LogObject.uart_send_str(F("Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) DEBUG_V2: Read bytes:")); + LogObject.uart_send_dec(len); + LogObject.uart_send_str(F(" save to block(")); + LogObject.uart_send_dec(handle); + LogObject.uart_send_str(F(") [")); + LogObject.uart_send_hex(position); + LogObject.uart_send_str(F("]: ")); + for (uint16_t i=0; i=LOG_DEBUG_V3 + LogObject.uart_send_str(F("Enc28J60Network::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) DEBUG_V3:Function started with len:")); + LogObject.uart_send_decln(len); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + memblock *packet = &blocks[handle]; + uint16_t start = packet->begin + position; + + writeRegPair(EWRPTL, start); + + if (len > packet->size - position) + len = packet->size - position; + writeBuffer(len, buffer); + #if ACTLOGLEVEL>=LOG_DEBUG_V2 + LogObject.uart_send_str(F("Enc28J60Network::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) DEBUG_V2: Write bytes:")); + LogObject.uart_send_dec(len); + LogObject.uart_send_str(F(" save to block(")); + LogObject.uart_send_dec(handle); + LogObject.uart_send_str(F(") [")); + LogObject.uart_send_hex(start); + LogObject.uart_send_str(F("]: ")); + for (uint16_t i=0; i=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::enableBroadcast (bool temporary) DEBUG_V3:Function started")); + #endif + writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_BCEN); + if(!temporary) + broadcast_enabled = true; +} + +void Enc28J60Network::disableBroadcast (bool temporary) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::disableBroadcast (bool temporary) DEBUG_V3:Function started")); + #endif + if(!temporary) + broadcast_enabled = false; + if(!broadcast_enabled) + writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_BCEN); +} + +void Enc28J60Network::enableMulticast (void) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::enableMulticast (void) DEBUG_V3:Function started")); + #endif + writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_MCEN); +} + +void Enc28J60Network::disableMulticast (void) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::disableMulticast (void) DEBUG_V3:Function started")); + #endif + writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_MCEN); +} + +uint8_t Enc28J60Network::readRegByte (uint8_t address) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::readRegByte (uint8_t address) DEBUG_V3:Function started")); + #endif + setBank(address); + return readOp(ENC28J60_READ_CTRL_REG, address); +} + +void Enc28J60Network::writeRegByte (uint8_t address, uint8_t data) { + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::writeRegByte (uint8_t address, uint8_t data) DEBUG_V3:Function started")); + #endif + setBank(address); + writeOp(ENC28J60_WRITE_CTRL_REG, address, data); +} + + +uint8_t Enc28J60Network::readByte(uint16_t addr) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::readByte(uint16_t addr) DEBUG_V3:Function started")); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + writeRegPair(ERDPTL, addr); + + CSACTIVE; + #if ENC28J60_USE_SPILIB + // issue read command + #if defined(ARDUINO) + SPI.transfer(ENC28J60_READ_BUF_MEM); + // read data + uint8_t c = SPI.transfer(0x00); + #endif + #if defined(__MBED__) + _spi.write(ENC28J60_READ_BUF_MEM); + // read data + uint8_t c = _spi.write(0x00); + #endif + CSPASSIVE; + return (c); + #else + // issue read command + SPDR = ENC28J60_READ_BUF_MEM; + waitspi(); + // read data + SPDR = 0x00; + waitspi(); + CSPASSIVE; + return (SPDR); + #endif +} + +void Enc28J60Network::writeByte(uint16_t addr, uint8_t data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::writeByte(uint16_t addr, uint8_t data) DEBUG_V3:Function started")); + #endif + #if defined(ESP8266) + wdt_reset(); + #endif + writeRegPair(EWRPTL, addr); + + CSACTIVE; + #if ENC28J60_USE_SPILIB + // issue write command + #if defined(ARDUINO) + SPI.transfer(ENC28J60_WRITE_BUF_MEM); + // write data + SPI.transfer(data); + #endif + #if defined(__MBED__) + _spi.write(ENC28J60_WRITE_BUF_MEM); + // write data + _spi.write(data); + #endif + #else + // issue write command + SPDR = ENC28J60_WRITE_BUF_MEM; + waitspi(); + // write data + SPDR = data; + waitspi(); + #endif + CSPASSIVE; +} + +void +Enc28J60Network::copyPacket(memhandle dest_pkt, memaddress dest_pos, memhandle src_pkt, memaddress src_pos, uint16_t len) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::copyPacket(memhandle dest_pkt, memaddress dest_pos, memhandle src_pkt, memaddress src_pos, uint16_t len) DEBUG_V3:Function started")); + #endif + memblock *dest = &blocks[dest_pkt]; + memblock *src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt]; + memaddress start = src_pkt == UIP_RECEIVEBUFFERHANDLE && src->begin + src_pos > RXSTOP_INIT ? src->begin + src_pos-RXSTOP_INIT+RXSTART_INIT : src->begin + src_pos; + enc28J60_mempool_block_move_callback(dest->begin+dest_pos,start,len); + // setERXRDPT(); let it to freePacket after all packets are saved +} + +void +enc28J60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("enc28J60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len) DEBUG_V3:Function started")); + #endif +//void +//Enc28J60Network::memblock_mv_cb(uint16_t dest, uint16_t src, uint16_t len) +//{ + //as ENC28J60 DMA is unable to copy single bytes: + if (len == 1) + { + Enc28J60Network::writeByte(dest,Enc28J60Network::readByte(src)); + } + else + { + // calculate address of last byte + len += src - 1; + + /* 1. Appropriately program the EDMAST, EDMAND + and EDMADST register pairs. The EDMAST + registers should point to the first byte to copy + from, the EDMAND registers should point to the + last byte to copy and the EDMADST registers + should point to the first byte in the destination + range. The destination range will always be + linear, never wrapping at any values except from + 8191 to 0 (the 8-Kbyte memory boundary). + Extreme care should be taken when + programming the start and end pointers to + prevent a never ending DMA operation which + would overwrite the entire 8-Kbyte buffer. + */ + Enc28J60Network::writeRegPair(EDMASTL, src); + Enc28J60Network::writeRegPair(EDMADSTL, dest); + + if ((src <= RXSTOP_INIT)&& (len > RXSTOP_INIT))len -= ((RXSTOP_INIT + 1)-RXSTART_INIT); + Enc28J60Network::writeRegPair(EDMANDL, len); + + /* + 2. If an interrupt at the end of the copy process is + desired, set EIE.DMAIE and EIE.INTIE and + clear EIR.DMAIF. + + 3. Verify that ECON1.CSUMEN is clear. */ + Enc28J60Network::writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN); + + /* 4. Start the DMA copy by setting ECON1.DMAST. */ + Enc28J60Network::writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST); + + // wait until runnig DMA is completed + while (Enc28J60Network::readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST) + { + delay(1); + } + } +} + +void +Enc28J60Network::freePacket(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::freePacket(void) DEBUG_V3:Function started")); + #endif + setERXRDPT(); +} + +uint8_t +Enc28J60Network::readOp(uint8_t op, uint8_t address) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::readOp(uint8_t op, uint8_t address) DEBUG_V3:Function started")); + #endif + CSACTIVE; + // issue read command + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + SPI.transfer(op | (address & ADDR_MASK)); + // read data + if(address & 0x80) + { + // do dummy read if needed (for mac and mii, see datasheet page 29) + SPI.transfer(0x00); + } + uint8_t c = SPI.transfer(0x00); + #endif + #if defined(__MBED__) + _spi.write(op | (address & ADDR_MASK)); + // read data + if(address & 0x80) + { + // do dummy read if needed (for mac and mii, see datasheet page 29) + _spi.write(0x00); + } + uint8_t c = _spi.write(0x00); + #endif + // release CS + CSPASSIVE; + return(c); + #else + // issue read command + SPDR = op | (address & ADDR_MASK); + waitspi(); + // read data + SPDR = 0x00; + waitspi(); + // do dummy read if needed (for mac and mii, see datasheet page 29) + if(address & 0x80) + { + SPDR = 0x00; + waitspi(); + } + // release CS + CSPASSIVE; + return(SPDR); + #endif + #if defined(ESP8266) + yield(); + #endif +} + +void +Enc28J60Network::writeOp(uint8_t op, uint8_t address, uint8_t data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::writeOp(uint8_t op, uint8_t address, uint8_t data) DEBUG_V3:Function started")); + #endif + CSACTIVE; + // issue write command + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + SPI.transfer(op | (address & ADDR_MASK)); + // write data + SPI.transfer(data); + #endif + #if defined(__MBED__) + _spi.write(op | (address & ADDR_MASK)); + // write data + _spi.write(data); + #endif + #else + // issue write command + SPDR = op | (address & ADDR_MASK); + waitspi(); + // write data + SPDR = data; + waitspi(); + #endif + CSPASSIVE; + #if defined(ESP8266) + yield(); + #endif +} + +void +Enc28J60Network::readBuffer(uint16_t len, uint8_t* data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::readBuffer(uint16_t len, uint8_t* data) DEBUG_V3:Function started")); + #endif + CSACTIVE; + // issue read command + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + SPI.transfer(ENC28J60_READ_BUF_MEM); + #endif + #if defined(__MBED__) + _spi.write(ENC28J60_READ_BUF_MEM); + #endif + #else + SPDR = ENC28J60_READ_BUF_MEM; + waitspi(); + #endif + while(len) + { + len--; + // read data + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + *data = SPI.transfer(0x00); + #endif + #if defined(__MBED__) + *data = _spi.write(0x00); + #endif + #else + SPDR = 0x00; + waitspi(); + *data = SPDR; + #endif + data++; + } + //*data='\0'; + CSPASSIVE; +} + +void +Enc28J60Network::writeBuffer(uint16_t len, uint8_t* data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::writeBuffer(uint16_t len, uint8_t* data) DEBUG_V3:Function started")); + #endif + CSACTIVE; + // issue write command + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + SPI.transfer(ENC28J60_WRITE_BUF_MEM); + #endif + #if defined(__MBED__) + _spi.write(ENC28J60_WRITE_BUF_MEM); + #endif + #else + SPDR = ENC28J60_WRITE_BUF_MEM; + waitspi(); + #endif + while(len) + { + len--; + // write data + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + SPI.transfer(*data); + #endif + #if defined(__MBED__) + _spi.write(*data); + #endif + data++; + #else + SPDR = *data; + data++; + waitspi(); + #endif + } + CSPASSIVE; +} + +void +Enc28J60Network::setBank(uint8_t address) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::setBank(uint8_t address) DEBUG_V3:Function started")); + #endif + // set the bank (if needed) + if((address & BANK_MASK) != bank) + { + // set the bank + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0)); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5); + bank = (address & BANK_MASK); + } +} + +uint8_t +Enc28J60Network::readReg(uint8_t address) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::readReg(uint8_t address) DEBUG_V3:Function started")); + #endif + // set the bank + setBank(address); + // do the read + return readOp(ENC28J60_READ_CTRL_REG, address); +} + +void +Enc28J60Network::writeReg(uint8_t address, uint8_t data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::writeReg(uint8_t address, uint8_t data) DEBUG_V3:Function started")); + #endif + // set the bank + setBank(address); + // do the write + writeOp(ENC28J60_WRITE_CTRL_REG, address, data); +} + +void +Enc28J60Network::writeRegPair(uint8_t address, uint16_t data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::writeRegPair(uint8_t address, uint16_t data) DEBUG_V3:Function started")); + #endif + // set the bank + setBank(address); + // do the write + writeOp(ENC28J60_WRITE_CTRL_REG, address, (data&0xFF)); + writeOp(ENC28J60_WRITE_CTRL_REG, address+1, (data) >> 8); +} + +void +Enc28J60Network::phyWrite(uint8_t address, uint16_t data) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::phyWrite(uint8_t address, uint16_t data) DEBUG_V3:Function started")); + #endif + unsigned int timeout = 15; + // set the PHY register address + writeReg(MIREGADR, address); + // write the PHY data + writeRegPair(MIWRL, data); + // wait until the PHY write completes + while (readReg(MISTAT) & MISTAT_BUSY) + { + delay(10); + #if defined(ESP8266) + wdt_reset(); + #endif + if (--timeout == 0) + { + #if ACTLOGLEVEL>=LOG_ERR + LogObject.uart_send_strln(F("Enc28J60Network::phyWrite ERROR:TIMEOUT !!")); + #endif + return; + } + } +} + +uint16_t +Enc28J60Network::phyRead(uint8_t address) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::phyRead(uint8_t address) DEBUG_V3:Function started")); + #endif + unsigned int timeout = 15; + writeReg(MIREGADR,address); + writeReg(MICMD, MICMD_MIIRD); + // wait until the PHY read completes + while(readReg(MISTAT) & MISTAT_BUSY) + { + delay(10); + #if defined(ESP8266) + wdt_reset(); + #endif + if (--timeout == 0) + { + #if ACTLOGLEVEL>=LOG_ERR + LogObject.uart_send_strln(F("Enc28J60Network::phyRead ERROR:TIMEOUT !!")); + #endif + return 0; + } + } + writeReg(MICMD, 0); + return (readReg(MIRDL) | readReg(MIRDH) << 8); +} + +void +Enc28J60Network::clkout(uint8_t clk) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::clkout(uint8_t clk) DEBUG_V3:Function started")); + #endif + //setup clkout: 2 is 12.5MHz: + writeReg(ECOCON, clk & 0x7); +} + +uint16_t +Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len) DEBUG_V3:Function started")); + #endif + uint16_t t; + len = setReadPtr(handle, pos, len)-1; + CSACTIVE; + // issue read command + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + SPI.transfer(ENC28J60_READ_BUF_MEM); + #endif + #if defined(__MBED__) + _spi.write(ENC28J60_READ_BUF_MEM); + #endif + #else + SPDR = ENC28J60_READ_BUF_MEM; + waitspi(); + #endif + uint16_t i; + for (i = 0; i < len; i+=2) + { + // read data + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + t = SPI.transfer(0x00) << 8; + t += SPI.transfer(0x00); + #endif + #if defined(__MBED__) + t = _spi.write(0x00) << 8; + t += _spi.write(0x00); + #endif + #else + SPDR = 0x00; + waitspi(); + t = SPDR << 8; + SPDR = 0x00; + waitspi(); + t += SPDR; + #endif + sum += t; + if(sum < t) + { + sum++; /* carry */ + } + } + if(i == len) + { + #if ENC28J60_USE_SPILIB + #if defined(ARDUINO) + t = (SPI.transfer(0x00) << 8) + 0; + #endif + #if defined(__MBED__) + t = (_spi.write(0x00) << 8) + 0; + #endif + #else + SPDR = 0x00; + waitspi(); + t = (SPDR << 8) + 0; + #endif + sum += t; + if(sum < t) + { + sum++; /* carry */ + } + } + CSPASSIVE; + + /* Return sum in host byte order. */ + return sum; +} + +void +Enc28J60Network::powerOff(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::powerOff(void) DEBUG_V3:Function started")); + #endif + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN); + delay(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS); + delay(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV); +} + +void +Enc28J60Network::powerOn(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::powerOn(void) DEBUG_V3:Function started")); + #endif + writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV); + delay(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + delay(50); +} + +// read erevid from object: +uint8_t +Enc28J60Network::geterevid(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_str(F("Enc28J60Network::geterevid(void) DEBUG_V3:Function started and return:")); + LogObject.uart_send_decln(erevid); + #endif + return(erevid); +} + +// read the phstat2 of the chip: +uint16_t +Enc28J60Network::PhyStatus(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_str(F("Enc28J60Network::PhyStatus(void) DEBUG_V3:Function started")); + LogObject.uart_send_decln(erevid); + #endif + uint16_t phstat2; + phstat2=phyRead(PHSTAT2); + if ((phstat2 & 0x20) > 0) {phstat2=phstat2 &0x100;} + phstat2=(phstat2 & 0xFF00) | erevid; + if ((phstat2 & 0x8000) > 0) {phstat2=0;} + return phstat2; +} + +bool +Enc28J60Network::linkStatus(void) +{ + #if ACTLOGLEVEL>=LOG_DEBUG_V3 + LogObject.uart_send_strln(F("Enc28J60Network::linkStatus(void) DEBUG_V3:Function started")); + #endif + return (phyRead(PHSTAT2) & 0x0400) > 0; +} + +Enc28J60Network Enc28J60; diff --git a/LibraryPatches/UIPEthernet/utility/Enc28J60Network.h b/LibraryPatches/UIPEthernet/utility/Enc28J60Network.h new file mode 100644 index 0000000..8f5e446 --- /dev/null +++ b/LibraryPatches/UIPEthernet/utility/Enc28J60Network.h @@ -0,0 +1,331 @@ +/* + Enc28J60NetworkClass.h + UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. + + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + inspired by enc28j60.c file from the AVRlib library by Pascal Stang. + For AVRlib See http://www.procyonengineering.com/ + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef Enc28J60Network_H_ +#define Enc28J60Network_H_ + +#if defined(ESP32) + //pin SS already defined in ESP32 as pin 5, don't use this as conflict with SPIFFS, EEPROM, etc. + // Use in GPIO13 + #warning ENC28J60Network.h => use ESP32, change ENC28J60_CONTROL_CS/SS_PIN_DEFAULT to GPIO13, MOSI(23), MISO(19), SCK(18) + #define ENC28J60_CONTROL_CS 13 +#endif + +// KH, For nRF52 +#if ( defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || defined(NRF52840_CLUE) || \ + defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #include + #define ENC28J60_USE_SPILIB 1 + + #ifndef USE_THIS_SS_PIN + // default to pin 10 + #define ENC28J60_CONTROL_CS 10 + #else + #warning Using USE_THIS_SS_PIN in Enc28J60Network.h for nRF52 + #define ENC28J60_CONTROL_CS USE_THIS_SS_PIN + #endif +#endif + +// KH, For SAMD21/SAMD51 +#if ( defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) \ + || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_SAMD_MKRFox1200) || defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) \ + || defined(ARDUINO_SAMD_MKRGSM1400) || defined(ARDUINO_SAMD_MKRNB1500) || defined(ARDUINO_SAMD_MKRVIDOR4000) || defined(__SAMD21G18A__) \ + || defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(__SAMD21E18A__) || defined(__SAMD51__) || defined(__SAMD51J20A__) || defined(__SAMD51J19A__) \ + || defined(__SAMD51G19A__) || defined(__SAMD51P19A__) || defined(__SAMD21G18A__) ) + #include + #define ENC28J60_USE_SPILIB 1 + + #ifndef USE_THIS_SS_PIN + // default to pin 10 + #define ENC28J60_CONTROL_CS 10 + #else + #warning Using USE_THIS_SS_PIN in Enc28J60Network.h for SAMD + #define ENC28J60_CONTROL_CS USE_THIS_SS_PIN + #endif +#endif + +#include "mempool.h" +#if defined(__MBED__) + #include + //UIPEthernet(SPI_MOSI, SPI_MISO, SPI_SCK, SPI_CS); + #if defined(TARGET_LPC1768) + #define SPI_MOSI p11 + #define SPI_MISO p12 + #define SPI_SCK p13 + #define SPI_CS p8 + #elif defined(TARGET_LPC1114) + #define SPI_MOSI dp2 + #define SPI_MISO dp1 + #define SPI_SCK dp6 + #define SPI_CS dp25 + #elif defined(TARGET_LPC11U68) + #define SPI_MOSI P0_9 + #define SPI_MISO P0_8 + #define SPI_SCK P1_29 + #define SPI_CS P0_2 + #elif defined(TARGET_NUCLEO_F103RB) || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_F030R8) \ + || defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F302R8) || defined(TARGET_NUCLEO_L053R8) \ + || defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F334R8) || defined(TARGET_NUCLEO_F072RB) \ + || defined(TARGET_NUCLEO_F091RC) || defined(TARGET_NUCLEO_F303RE) || defined(TARGET_NUCLEO_F070RB) + #define SPI_MOSI D4 + #define SPI_MISO D5 + #define SPI_SCK D3 + #define SPI_CS D2 + #endif + #define ENC28J60_CONTROL_CS SPI_CS +#endif + +#if defined(STM32F3) || defined(STM32F2) //This is workaround for stm32duino STM32F2, and adafruit wiced feather STM32F2 + #define BOARD_SPI1_NSS_PIN PA4 + #define BOARD_SPI1_SCK_PIN PA5 + #define BOARD_SPI1_MISO_PIN PA6 + #define BOARD_SPI1_MOSI_PIN PA7 +#endif //This is workaround for stm32duino STM32F3, and adafruit wiced feather STM32F2 + +#if defined(BOARD_discovery_f4) + #define __STM32F4__ +#endif +#if defined(__MK20DX128__) || defined(__MKL26Z64__) + #include +#endif + +#if !defined(ENC28J60_CONTROL_CS) + #if defined(__AVR__) || defined(ESP8266) || defined(__RFduino__) + // Arduino Uno (__AVR__) SS defined to pin 10 + // Arduino Leonardo (ARDUINO_AVR_LEONARDO) SS defined to LED_BUILTIN_RX (17) + // Arduino Mega(__AVR_ATmega2560__) SS defined to pin 53 + // ESP8266 (ESP8266) SS defined to pin 15 + #if defined(ARDUINO_AVR_LEONARDO) || defined(ARDUINO_AVR_MICRO) + #define ENC28J60_CONTROL_CS PIN_A10 + #warning "Using LEONARDO borad PIN_A10 for ENC28J60_CONTROL_CS. Use UIPEthernet::init(uint8_t) to change it." + #else + #define ENC28J60_CONTROL_CS SS + #endif + #elif defined(ARDUINO_ARCH_AMEBA) //Defined SS to pin 10 + #define ENC28J60_CONTROL_CS SS //PC_0 A5 10 + #elif defined(ARDUINO_ARCH_SAM) + // Arduino Due (ARDUINO_ARCH_SAM) BOARD_SPI_DEFAULT_SS (SS3) defined to pin 78 + //#define ENC28J60_CONTROL_CS BOARD_SPI_DEFAULT_SS + #define ENC28J60_CONTROL_CS BOARD_SPI_SS0 + #elif defined(ARDUINO_ARCH_SAMD) + #define ENC28J60_CONTROL_CS SS + #elif defined(__ARDUINO_ARC__) //Intel ARC32 Genuino 101 + #define ENC28J60_CONTROL_CS SS + #elif defined(__RFduino__) //RFduino + #define ENC28J60_CONTROL_CS SS + #elif defined(ARDUINO_ARCH_STM32) // STM32duino core + #define ENC28J60_CONTROL_CS SS + #elif defined(ARDUINO_ARCH_ESP32) // arduino-esp32 + #define ENC28J60_CONTROL_CS SS + #elif defined(STM32_MCU_SERIES) || defined(__STM32F1__) || defined(__STM32F3__) || defined(STM32F3) || defined(__STM32F4__) || defined(STM32F2) + #if defined(BOARD_SPI1_NSS_PIN) + #define ENC28J60_CONTROL_CS BOARD_SPI1_NSS_PIN + #elif defined(ARDUINO_STM32F4_NETDUINO2PLUS) + #define ENC28J60_CONTROL_CS PC8 + #else + #define ENC28J60_CONTROL_CS SPI.nssPin() + //#define ENC28J60_CONTROL_CS PA4 + #endif + #elif defined(__MK20DX128__) || defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) + #define ENC28J60_CONTROL_CS PIN_SPI_SS + #endif +#endif +#if !defined(ENC28J60_CONTROL_CS) + #warning "Default ENC28J60_CONTROL_CS could not be defined! Use UIPEthernet::init(uint8_t) to set it." + #define ENC28J60_CONTROL_CS 0 +#endif + +extern uint8_t ENC28J60ControlCS; + +#if !defined(SPI_MOSI) + #if defined(__AVR__) || defined(ESP8266) || defined(__RFduino__) + #define SPI_MOSI MOSI + #elif defined(ARDUINO_ARCH_AMEBA) + #define SPI_MOSI 11 //PC_2 + #elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) + #define SPI_MOSI PIN_SPI_MOSI + #elif defined(__ARDUINO_ARC__) //Intel ARC32 Genuino 101 + #define SPI_MOSI MOSI + #elif defined(__RFduino__) //RFduino + #define SPI_MOSI MOSI + #elif defined(ARDUINO_ARCH_STM32) // STM32duino core + #define SPI_MOSI MOSI + #elif defined(ARDUINO_ARCH_ESP32) // arduino-esp32 + #define SPI_MOSI MOSI + #elif defined(STM32_MCU_SERIES) || defined(__STM32F1__) || defined(__STM32F3__) || defined(STM32F3) || defined(__STM32F4__) || defined(STM32F2) + #if defined(BOARD_SPI1_MOSI_PIN) + #define SPI_MOSI BOARD_SPI1_MOSI_PIN + #else + #define SPI_MOSI SPI.mosiPin() + #endif + #elif defined(__MK20DX128__) || defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) + #define SPI_MOSI PIN_SPI_MOSI + #endif +#endif +#if !defined(SPI_MOSI) + //#error "Not defined SPI_MOSI!" + #define SPI_MOSI MOSI +#endif + +#if !defined(SPI_MISO) + #if defined(__AVR__) || defined(ESP8266) || defined(__RFduino__) + #define SPI_MISO MISO + #elif defined(ARDUINO_ARCH_AMEBA) + #define SPI_MISO 12 //PC_3 + #elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) + #define SPI_MISO PIN_SPI_MISO + #elif defined(__ARDUINO_ARC__) //Intel ARC32 Genuino 101 + #define SPI_MISO MISO + #elif defined(__RFduino__) //RFduino + #define SPI_MISO MISO + #elif defined(ARDUINO_ARCH_STM32) // STM32duino core + #define SPI_MISO MISO + #elif defined(ARDUINO_ARCH_ESP32) // arduino-esp32 + #define SPI_MISO MISO + #elif defined(STM32_MCU_SERIES) || defined(__STM32F1__) || defined(__STM32F3__) || defined(STM32F3) || defined(__STM32F4__) || defined(STM32F2) + #if defined(BOARD_SPI1_MISO_PIN) + #define SPI_MISO BOARD_SPI1_MISO_PIN + #else + #define SPI_MISO SPI.misoPin() + #endif + #elif defined(__MK20DX128__) || defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) + #define SPI_MISO PIN_SPI_MISO + #endif +#endif +#if !defined(SPI_MISO) + //#error "Not defined SPI_MISO!" + #define SPI_MISO MISO +#endif +#if !defined(SPI_SCK) + #if defined(__AVR__) || defined(ESP8266) || defined(__RFduino__) + #define SPI_SCK SCK + #elif defined(ARDUINO_ARCH_AMEBA) + #define SPI_SCK 13 //PC_1 A4 + #elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) + #define SPI_SCK PIN_SPI_SCK + #elif defined(__ARDUINO_ARC__) //Intel ARC32 Genuino 101 + #define SPI_SCK SCK + #elif defined(__RFduino__) //RFduino + #define SPI_SCK SCK + #elif defined(ARDUINO_ARCH_STM32) // STM32duino core + #define SPI_SCK SCK + #elif defined(ARDUINO_ARCH_ESP32) // arduino-esp32 + #define SPI_SCK SCK + #elif defined(STM32_MCU_SERIES) || defined(__STM32F1__) || defined(__STM32F3__) || defined(STM32F3) || defined(__STM32F4__) || defined(STM32F2) + #if defined(BOARD_SPI1_SCK_PIN) + #define SPI_SCK BOARD_SPI1_SCK_PIN + #else + #define SPI_SCK SPI.sckPin() + #endif + #elif defined(__MK20DX128__) || defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) + #define SPI_SCK PIN_SPI_SCK + #endif +#endif + +#if !defined(SPI_SCK) + // For nRF52 + //#error "Not defined SPI_SCK!" + #define SPI_SCK SCK +#endif + +#if defined(__MBED__) || defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) || defined(__ARDUINO_ARC__) || defined(__STM32F1__) || defined(__STM32F3__) || defined(STM32F3) || defined(__STM32F4__) || defined(STM32F2) || defined(ESP8266) || defined(ARDUINO_ARCH_AMEBA) || defined(__MK20DX128__) || defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) || defined(__RFduino__) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) + #if defined(ARDUINO) && defined(STM32F3) + #include "HardwareSPI.h" + #else + #include + #endif + #define ENC28J60_USE_SPILIB 1 +#endif + + + +#define UIP_RECEIVEBUFFERHANDLE 0xff + +/* + * Empfangen von ip-header, arp etc... + * wenn tcp/udp -> tcp/udp-callback -> assign new packet to connection + */ + +#define TX_COLLISION_RETRY_COUNT 10 + +class Enc28J60Network : public MemoryPool +{ + +private: + static uint16_t nextPacketPtr; + static uint8_t bank; + static uint8_t erevid; + + static struct memblock receivePkt; + + static bool broadcast_enabled; //!< True if broadcasts enabled (used to allow temporary disable of broadcast for DHCP or other internal functions) + + static uint8_t readOp(uint8_t op, uint8_t address); + static void writeOp(uint8_t op, uint8_t address, uint8_t data); + static uint16_t setReadPtr(memhandle handle, memaddress position, uint16_t len); + static void setERXRDPT(void); + static void readBuffer(uint16_t len, uint8_t* data); + static void writeBuffer(uint16_t len, uint8_t* data); + static uint8_t readByte(uint16_t addr); + static void writeByte(uint16_t addr, uint8_t data); + static void setBank(uint8_t address); + static uint8_t readReg(uint8_t address); + static void writeReg(uint8_t address, uint8_t data); + static void writeRegPair(uint8_t address, uint16_t data); + static void phyWrite(uint8_t address, uint16_t data); + static uint16_t phyRead(uint8_t address); + static void clkout(uint8_t clk); + + static void enableBroadcast (bool temporary); + static void disableBroadcast (bool temporary); + static void enableMulticast (void); + static void disableMulticast (void); + + static uint8_t readRegByte (uint8_t address); + static void writeRegByte (uint8_t address, uint8_t data); + + friend void enc28J60_mempool_block_move_callback(memaddress,memaddress,memaddress); + +public: + + void powerOn(void); + void powerOff(void); + static uint8_t geterevid(void); + uint16_t PhyStatus(void); + static bool linkStatus(void); + + static void init(uint8_t* macaddr); + static memhandle receivePacket(void); + static void freePacket(void); + static memaddress blockSize(memhandle handle); + static void sendPacket(memhandle handle); + static uint16_t readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); + static uint16_t writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); + static void copyPacket(memhandle dest, memaddress dest_pos, memhandle src, memaddress src_pos, uint16_t len); + static uint16_t chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len); +}; + +extern Enc28J60Network Enc28J60; +#endif /* Enc28J60NetworkClass_H_ */ diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.19.0/boards.txt b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/boards.txt new file mode 100644 index 0000000..bbe9f9e --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/boards.txt @@ -0,0 +1,649 @@ +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# Copyright (c) 2016 Sandeep Mistry All right reserved. +# Copyright (c) 2017 Adafruit Industries. 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 + +menu.softdevice=Bootloader +menu.debug=Debug + +# ---------------------------------- +# Bluefruit Feather nRF52832 +# ---------------------------------- +feather52832.name=Adafruit Feather nRF52832 +feather52832.bootloader.tool=bootburn + +# Upload +feather52832.upload.tool=nrfutil +feather52832.upload.protocol=nrfutil +feather52832.upload.use_1200bps_touch=false +feather52832.upload.wait_for_upload_port=false +feather52832.upload.native_usb=false +feather52832.upload.maximum_size=290816 +feather52832.upload.maximum_data_size=52224 + +# Build +feather52832.build.mcu=cortex-m4 +feather52832.build.f_cpu=64000000 +feather52832.build.board=NRF52832_FEATHER +feather52832.build.core=nRF5 +feather52832.build.variant=feather_nrf52832 +feather52840.build.usb_manufacturer="Adafruit LLC" +feather52840.build.usb_product="Feather nRF52832" +feather52832.build.extra_flags=-DNRF52832_XXAA -DNRF52832_FEATHER -DNRF52 +feather52832.build.ldscript=nrf52832_s132_v6.ld + +# SofDevice Menu +feather52832.menu.softdevice.s132v6=0.3.2 SoftDevice s132 6.1.1 +feather52832.menu.softdevice.s132v6.build.sd_name=s132 +feather52832.menu.softdevice.s132v6.build.sd_version=6.1.1 +feather52832.menu.softdevice.s132v6.build.sd_fwid=0x00B7 + +# Debug Menu +feather52832.menu.debug.l0=Level 0 (Release) +feather52832.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +feather52832.menu.debug.l1=Level 1 (Error Message) +feather52832.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +feather52832.menu.debug.l2=Level 2 (Full Debug) +feather52832.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +feather52832.menu.debug.l3=Level 3 (Segger SystemView) +feather52832.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +feather52832.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Bluefruit Feather nRF52840 Express +# ---------------------------------- +feather52840.name=Adafruit Feather nRF52840 Express + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +feather52840.vid.0=0x239A +feather52840.pid.0=0x8029 +feather52840.vid.1=0x239A +feather52840.pid.1=0x0029 +feather52840.vid.2=0x239A +feather52840.pid.2=0x002A +feather52840.vid.3=0x239A +feather52840.pid.3=0x802A + +# Upload +feather52840.bootloader.tool=bootburn +feather52840.upload.tool=nrfutil +feather52840.upload.protocol=nrfutil +feather52840.upload.use_1200bps_touch=true +feather52840.upload.wait_for_upload_port=true +feather52840.upload.maximum_size=815104 +feather52840.upload.maximum_data_size=237568 + +# Build +feather52840.build.mcu=cortex-m4 +feather52840.build.f_cpu=64000000 +feather52840.build.board=NRF52840_FEATHER +feather52840.build.core=nRF5 +feather52840.build.variant=feather_nrf52840_express +feather52840.build.usb_manufacturer="Adafruit LLC" +feather52840.build.usb_product="Feather nRF52840 Express" +feather52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_FEATHER {build.flags.usb} +feather52840.build.ldscript=nrf52840_s140_v6.ld +feather52840.build.vid=0x239A +feather52840.build.pid=0x8029 + +# SofDevice Menu +feather52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +feather52840.menu.softdevice.s140v6.build.sd_name=s140 +feather52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +feather52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +feather52840.menu.debug.l0=Level 0 (Release) +feather52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +feather52840.menu.debug.l1=Level 1 (Error Message) +feather52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +feather52840.menu.debug.l2=Level 2 (Full Debug) +feather52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +feather52840.menu.debug.l3=Level 3 (Segger SystemView) +feather52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +feather52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + +# ---------------------------------- +# Feather Bluefruit sense +# ---------------------------------- +feather52840sense.name=Adafruit Feather Bluefruit Sense + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +feather52840sense.vid.0=0x239A +feather52840sense.pid.0=0x8087 +feather52840sense.vid.1=0x239A +feather52840sense.pid.1=0x0087 +feather52840sense.vid.2=0x239A +feather52840sense.pid.2=0x0088 +feather52840sense.vid.3=0x239A +feather52840sense.pid.3=0x8088 + +# Upload +feather52840sense.bootloader.tool=bootburn +feather52840sense.upload.tool=nrfutil +feather52840sense.upload.protocol=nrfutil +feather52840sense.upload.use_1200bps_touch=true +feather52840sense.upload.wait_for_upload_port=true +feather52840sense.upload.maximum_size=815104 +feather52840sense.upload.maximum_data_size=237568 + +# Build +feather52840sense.build.mcu=cortex-m4 +feather52840sense.build.f_cpu=64000000 +feather52840sense.build.board=NRF52840_FEATHER_SENSE +feather52840sense.build.core=nRF5 +feather52840sense.build.variant=feather_nrf52840_sense +feather52840sense.build.usb_manufacturer="Adafruit LLC" +feather52840sense.build.usb_product="Feather nRF52840 Sense" +feather52840sense.build.extra_flags=-DNRF52840_XXAA -DNRF52840_FEATHER_SENSE {build.flags.usb} +feather52840sense.build.ldscript=nrf52840_s140_v6.ld +feather52840sense.build.vid=0x239A +feather52840sense.build.pid=0x8087 + +# SofDevice Menu +feather52840sense.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +feather52840sense.menu.softdevice.s140v6.build.sd_name=s140 +feather52840sense.menu.softdevice.s140v6.build.sd_version=6.1.1 +feather52840sense.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +feather52840sense.menu.debug.l0=Level 0 (Release) +feather52840sense.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +feather52840sense.menu.debug.l1=Level 1 (Error Message) +feather52840sense.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +feather52840sense.menu.debug.l2=Level 2 (Full Debug) +feather52840sense.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +feather52840sense.menu.debug.l3=Level 3 (Segger SystemView) +feather52840sense.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +feather52840sense.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + +# --------------------------------------------- +# Bluefruit ItsyBitsy nRF52840 Express +# --------------------------------------------- +itsybitsy52840.name=Adafruit ItsyBitsy nRF52840 Express + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +itsybitsy52840.vid.0=0x239A +itsybitsy52840.pid.0=0x8051 +itsybitsy52840.vid.1=0x239A +itsybitsy52840.pid.1=0x0051 +itsybitsy52840.vid.2=0x239A +itsybitsy52840.pid.2=0x0052 +itsybitsy52840.vid.3=0x239A +itsybitsy52840.pid.3=0x8052 + +# Upload +itsybitsy52840.bootloader.tool=bootburn +itsybitsy52840.upload.tool=nrfutil +itsybitsy52840.upload.protocol=nrfutil +itsybitsy52840.upload.use_1200bps_touch=true +itsybitsy52840.upload.wait_for_upload_port=true +itsybitsy52840.upload.maximum_size=815104 +itsybitsy52840.upload.maximum_data_size=237568 + +# Build +itsybitsy52840.build.mcu=cortex-m4 +itsybitsy52840.build.f_cpu=64000000 +itsybitsy52840.build.board=NRF52840_ITSYBITSY +itsybitsy52840.build.core=nRF5 +itsybitsy52840.build.variant=itsybitsy_nrf52840_express +itsybitsy52840.build.usb_manufacturer="Adafruit LLC" +itsybitsy52840.build.usb_product="ItsyBitsy nRF52840 Express" +itsybitsy52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_ITSYBITSY -DARDUINO_NRF52_ITSYBITSY {build.flags.usb} +itsybitsy52840.build.ldscript=nrf52840_s140_v6.ld +itsybitsy52840.build.vid=0x239A +itsybitsy52840.build.pid=0x8051 + +# SofDevice Menu +itsybitsy52840.menu.softdevice.s140v6=0.2.11 SoftDevice s140 6.1.1 +itsybitsy52840.menu.softdevice.s140v6.build.sd_name=s140 +itsybitsy52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +itsybitsy52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +itsybitsy52840.menu.debug.l0=Level 0 (Release) +itsybitsy52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +itsybitsy52840.menu.debug.l1=Level 1 (Error Message) +itsybitsy52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +itsybitsy52840.menu.debug.l2=Level 2 (Full Debug) +itsybitsy52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +itsybitsy52840.menu.debug.l3=Level 3 (Segger SystemView) +itsybitsy52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +itsybitsy52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# --------------------------------------------- +# Bluefruit Circuit Playground nRF52840 Express +# --------------------------------------------- +cplaynrf52840.name=Adafruit Circuit Playground Bluefruit + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +cplaynrf52840.vid.0=0x239A +cplaynrf52840.pid.0=0x8045 +cplaynrf52840.vid.1=0x239A +cplaynrf52840.pid.1=0x0045 +cplaynrf52840.vid.2=0x239A +cplaynrf52840.pid.2=0x0046 +cplaynrf52840.vid.3=0x239A +cplaynrf52840.pid.3=0x8046 + +# Upload +cplaynrf52840.bootloader.tool=bootburn +cplaynrf52840.upload.tool=nrfutil +cplaynrf52840.upload.protocol=nrfutil +cplaynrf52840.upload.use_1200bps_touch=true +cplaynrf52840.upload.wait_for_upload_port=true +cplaynrf52840.upload.maximum_size=815104 +cplaynrf52840.upload.maximum_data_size=237568 + +# Build +cplaynrf52840.build.mcu=cortex-m4 +cplaynrf52840.build.f_cpu=64000000 +cplaynrf52840.build.board=NRF52840_CIRCUITPLAY +cplaynrf52840.build.core=nRF5 +cplaynrf52840.build.variant=circuitplayground_nrf52840 +cplaynrf52840.build.usb_manufacturer="Adafruit LLC" +cplaynrf52840.build.usb_product="Circuit Playground Bluefruit" +cplaynrf52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_CIRCUITPLAY {build.flags.usb} +cplaynrf52840.build.ldscript=nrf52840_s140_v6.ld +cplaynrf52840.build.vid=0x239A +cplaynrf52840.build.pid=0x8045 + +# SofDevice Menu +cplaynrf52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +cplaynrf52840.menu.softdevice.s140v6.build.sd_name=s140 +cplaynrf52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +cplaynrf52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +cplaynrf52840.menu.debug.l0=Level 0 (Release) +cplaynrf52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +cplaynrf52840.menu.debug.l1=Level 1 (Error Message) +cplaynrf52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +cplaynrf52840.menu.debug.l2=Level 2 (Full Debug) +cplaynrf52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +cplaynrf52840.menu.debug.l3=Level 3 (Segger SystemView) +cplaynrf52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +cplaynrf52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + +# --------------------------------------------- +# Clue nRF52840 +# --------------------------------------------- +cluenrf52840.name=Adafruit CLUE + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +cluenrf52840.vid.0=0x239A +cluenrf52840.pid.0=0x8072 +cluenrf52840.vid.1=0x239A +cluenrf52840.pid.1=0x0072 +cluenrf52840.vid.2=0x239A +cluenrf52840.pid.2=0x0071 +cluenrf52840.vid.3=0x239A +cluenrf52840.pid.3=0x8071 + +# Upload +cluenrf52840.bootloader.tool=bootburn +cluenrf52840.upload.tool=nrfutil +cluenrf52840.upload.protocol=nrfutil +cluenrf52840.upload.use_1200bps_touch=true +cluenrf52840.upload.wait_for_upload_port=true +cluenrf52840.upload.maximum_size=815104 +cluenrf52840.upload.maximum_data_size=237568 + +# Build +cluenrf52840.build.mcu=cortex-m4 +cluenrf52840.build.f_cpu=64000000 +cluenrf52840.build.board=NRF52840_CLUE +cluenrf52840.build.core=nRF5 +cluenrf52840.build.variant=clue_nrf52840 +cluenrf52840.build.usb_manufacturer="Adafruit LLC" +cluenrf52840.build.usb_product="CLUE" +cluenrf52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_CLUE {build.flags.usb} +cluenrf52840.build.ldscript=nrf52840_s140_v6.ld +cluenrf52840.build.vid=0x239A +cluenrf52840.build.pid=0x8071 + +# SofDevice Menu +cluenrf52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +cluenrf52840.menu.softdevice.s140v6.build.sd_name=s140 +cluenrf52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +cluenrf52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +cluenrf52840.menu.debug.l0=Level 0 (Release) +cluenrf52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +cluenrf52840.menu.debug.l1=Level 1 (Error Message) +cluenrf52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +cluenrf52840.menu.debug.l2=Level 2 (Full Debug) +cluenrf52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +cluenrf52840.menu.debug.l3=Level 3 (Segger SystemView) +cluenrf52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +cluenrf52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Bluefruit Metro nRF52840 Express +# ---------------------------------- +metro52840.name=Adafruit Bluefruit Metro nRF52840 Express + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +metro52840.vid.0=0x239A +metro52840.pid.0=0x803F +metro52840.vid.1=0x239A +metro52840.pid.1=0x003F +metro52840.vid.2=0x239A +metro52840.pid.2=0x0040 +metro52840.vid.3=0x239A +metro52840.pid.3=0x8040 + +# Upload +metro52840.bootloader.tool=bootburn +metro52840.upload.tool=nrfutil +metro52840.upload.protocol=nrfutil +metro52840.upload.use_1200bps_touch=true +metro52840.upload.wait_for_upload_port=true +metro52840.upload.maximum_size=815104 +metro52840.upload.maximum_data_size=237568 + +# Build +metro52840.build.mcu=cortex-m4 +metro52840.build.f_cpu=64000000 +metro52840.build.board=NRF52840_METRO +metro52840.build.core=nRF5 +metro52840.build.variant=metro_nrf52840_express +metro52840.build.usb_manufacturer="Adafruit LLC" +metro52840.build.usb_product="Metro nRF52840 Express" +metro52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_METRO {build.flags.usb} +metro52840.build.ldscript=nrf52840_s140_v6.ld +metro52840.build.vid=0x239A +metro52840.build.pid=0x803F + +# SofDevice Menu +metro52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +metro52840.menu.softdevice.s140v6.build.sd_name=s140 +metro52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +metro52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +metro52840.menu.debug.l0=Level 0 (Release) +metro52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +metro52840.menu.debug.l1=Level 1 (Error Message) +metro52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +metro52840.menu.debug.l2=Level 2 (Full Debug) +metro52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +metro52840.menu.debug.l3=Level 3 (Segger SystemView) +metro52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +metro52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + + + +# ------------------------------------------------------- +# +# Boards that aren't made by Adafruit +# +# ------------------------------------------------------- + + +# ---------------------------------- +# Nordic nRF52840DK (PCA10056) +# ---------------------------------- +pca10056.name=Nordic nRF52840DK (PCA10056) +pca10056.bootloader.tool=bootburn + +# Upload +pca10056.upload.tool=nrfutil +pca10056.upload.protocol=nrfutil +pca10056.upload.use_1200bps_touch=true +pca10056.upload.wait_for_upload_port=true +pca10056.upload.maximum_size=815104 +pca10056.upload.maximum_data_size=237568 + +# Build +pca10056.build.mcu=cortex-m4 +pca10056.build.f_cpu=64000000 +pca10056.build.board=NRF52840_PCA10056 +pca10056.build.core=nRF5 +pca10056.build.variant=pca10056 +pca10056.build.usb_manufacturer="Nordic" +pca10056.build.usb_product="nRF52840 DK" +pca10056.build.extra_flags=-DNRF52840_XXAA -DNRF52840_PCA10056 {build.flags.usb} +pca10056.build.ldscript=nrf52840_s140_v6.ld +pca10056.build.vid=0x239A +pca10056.build.pid=0x8029 + +# SofDevice Menu +pca10056.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +pca10056.menu.softdevice.s140v6.build.sd_name=s140 +pca10056.menu.softdevice.s140v6.build.sd_version=6.1.1 +pca10056.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +pca10056.menu.debug.l0=Level 0 (Release) +pca10056.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +pca10056.menu.debug.l1=Level 1 (Error Message) +pca10056.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +pca10056.menu.debug.l2=Level 2 (Full Debug) +pca10056.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +pca10056.menu.debug.l3=Level 3 (Segger SystemView) +pca10056.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +pca10056.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Particle Xenon +# ---------------------------------- +particle_xenon.name=Particle Xenon + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +particle_xenon.vid.0=0x239A +particle_xenon.pid.0=0x8029 +particle_xenon.vid.1=0x239A +particle_xenon.pid.1=0x0029 +particle_xenon.vid.2=0x239A +particle_xenon.pid.2=0x002A +particle_xenon.vid.3=0x239A +particle_xenon.pid.3=0x802A + +# Upload +particle_xenon.bootloader.tool=bootburn +particle_xenon.upload.tool=nrfutil +particle_xenon.upload.protocol=nrfutil +particle_xenon.upload.use_1200bps_touch=true +particle_xenon.upload.wait_for_upload_port=true +particle_xenon.upload.maximum_size=815104 +particle_xenon.upload.maximum_data_size=237568 + +# Build +particle_xenon.build.mcu=cortex-m4 +particle_xenon.build.f_cpu=64000000 +particle_xenon.build.board=PARTICLE_XENON +particle_xenon.build.core=nRF5 +particle_xenon.build.variant=particle_xenon +particle_xenon.build.usb_manufacturer="Particle Industries" +particle_xenon.build.usb_product="Particle Xenon" +particle_xenon.build.extra_flags=-DNRF52840_XXAA -DPARTICLE_XENON {build.flags.usb} +particle_xenon.build.ldscript=nrf52840_s140_v6.ld +particle_xenon.build.vid=0x239A +particle_xenon.build.pid=0x8029 + +# SofDevice Menu +particle_xenon.menu.softdevice.s140v6=0.2.11 SoftDevice s140 6.1.1 +particle_xenon.menu.softdevice.s140v6.build.sd_name=s140 +particle_xenon.menu.softdevice.s140v6.build.sd_version=6.1.1 +particle_xenon.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +particle_xenon.menu.debug.l0=Level 0 (Release) +particle_xenon.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +particle_xenon.menu.debug.l1=Level 1 (Error Message) +particle_xenon.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +particle_xenon.menu.debug.l2=Level 2 (Full Debug) +particle_xenon.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +particle_xenon.menu.debug.l3=Level 3 (Segger SystemView) +particle_xenon.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +particle_xenon.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Raytac MDBT50Q - RX +# ---------------------------------- +mdbt50qrx.name=Raytac MDBT50Q-RX Dongle + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +mdbt50qrx.vid.0=0x239A +mdbt50qrx.pid.0=0x8029 +mdbt50qrx.vid.1=0x239A +mdbt50qrx.pid.1=0x0029 +mdbt50qrx.vid.2=0x239A +mdbt50qrx.pid.2=0x002A +mdbt50qrx.vid.3=0x239A +mdbt50qrx.pid.3=0x802A + +# Upload +mdbt50qrx.bootloader.tool=bootburn +mdbt50qrx.upload.tool=nrfutil +mdbt50qrx.upload.protocol=nrfutil +mdbt50qrx.upload.use_1200bps_touch=true +mdbt50qrx.upload.wait_for_upload_port=true +mdbt50qrx.upload.maximum_size=815104 +mdbt50qrx.upload.maximum_data_size=237568 + +# Build +mdbt50qrx.build.mcu=cortex-m4 +mdbt50qrx.build.f_cpu=64000000 +mdbt50qrx.build.board=MDBT50Q_RX +mdbt50qrx.build.core=nRF5 +mdbt50qrx.build.variant=raytac_mdbt50q_rx +mdbt50qrx.build.usb_manufacturer="Raytac Corporation" +mdbt50qrx.build.usb_product="Raytac MDBT50Q - RX" +mdbt50qrx.build.extra_flags=-DNRF52840_XXAA -DMDBT50Q_RX {build.flags.usb} +mdbt50qrx.build.ldscript=nrf52840_s140_v6.ld +mdbt50qrx.build.vid=0x239A +mdbt50qrx.build.pid=0x8029 + +# SofDevice Menu +mdbt50qrx.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +mdbt50qrx.menu.softdevice.s140v6.build.sd_name=s140 +mdbt50qrx.menu.softdevice.s140v6.build.sd_version=6.1.1 +mdbt50qrx.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +mdbt50qrx.menu.debug.l0=Level 0 (Release) +mdbt50qrx.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +mdbt50qrx.menu.debug.l1=Level 1 (Error Message) +mdbt50qrx.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +mdbt50qrx.menu.debug.l2=Level 2 (Full Debug) +mdbt50qrx.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +mdbt50qrx.menu.debug.l3=Level 3 (Segger SystemView) +mdbt50qrx.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +mdbt50qrx.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# NINA B302 +# ---------------------------------- +ninab302.name=NINA B302 ublox + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +ninab302.vid.0=0x239A +ninab302.pid.0=0x8029 +ninab302.vid.1=0x239A +ninab302.pid.1=0x0029 +ninab302.vid.2=0x7239A +ninab302.pid.2=0x002A +ninab302.vid.3=0x239A +ninab302.pid.3=0x802A + +# Upload +ninab302.bootloader.tool=bootburn +ninab302.upload.tool=nrfutil +ninab302.upload.protocol=nrfutil +ninab302.upload.use_1200bps_touch=true +ninab302.upload.wait_for_upload_port=true +ninab302.upload.maximum_size=815104 +ninab302.upload.maximum_data_size=237568 + +# Build +ninab302.build.mcu=cortex-m4 +ninab302.build.f_cpu=64000000 +ninab302.build.board=NINA_B302_ublox +ninab302.build.core=nRF5 +ninab302.build.variant=NINA_B302_ublox +ninab302.build.usb_manufacturer="Nordic" +ninab302.build.usb_product="NINA B302 ublox" +ninab302.build.extra_flags=-DNRF52840_XXAA -DNINA_B302_ublox {build.flags.usb} +ninab302.build.ldscript=nrf52840_s140_v6.ld +ninab302.build.vid=0x239A +ninab302.build.pid=0x8029 + +# SofDevice Menu +ninab302.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +ninab302.menu.softdevice.s140v6.build.sd_name=s140 +ninab302.menu.softdevice.s140v6.build.sd_version=6.1.1 +ninab302.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +ninab302.menu.debug.l0=Level 0 (Release) +ninab302.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +ninab302.menu.debug.l1=Level 1 (Error Message) +ninab302.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +ninab302.menu.debug.l2=Level 2 (Full Debug) +ninab302.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +ninab302.menu.debug.l3=Level 3 (Segger SystemView) +ninab302.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +ninab302.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# NINA B112 +# ---------------------------------- +ninab112.name=NINA B112 ublox +ninab112.bootloader.tool=bootburn + +# Upload +ninab112.upload.tool=nrfutil +ninab112.upload.protocol=nrfutil +ninab112.upload.use_1200bps_touch=false +ninab112.upload.wait_for_upload_port=false +ninab112.upload.native_usb=false +ninab112.upload.maximum_size=290816 +ninab112.upload.maximum_data_size=52224 + +# Build +ninab112.build.mcu=cortex-m4 +ninab112.build.f_cpu=64000000 +ninab112.build.board=NINA_B112_ublox +ninab112.build.core=nRF5 +ninab112.build.variant=NINA_B112_ublox +feather52840.build.usb_manufacturer="Adafruit LLC" +feather52840.build.usb_product="Feather nRF52832" +ninab112.build.extra_flags=-DNRF52832_XXAA -DNINA_B112_ublox -DNRF52 +ninab112.build.ldscript=nrf52832_s132_v6.ld + +# SofDevice Menu +ninab112.menu.softdevice.s132v6=0.3.2 SoftDevice s132 6.1.1 +ninab112.menu.softdevice.s132v6.build.sd_name=s132 +ninab112.menu.softdevice.s132v6.build.sd_version=6.1.1 +ninab112.menu.softdevice.s132v6.build.sd_fwid=0x00B7 + +# Debug Menu +ninab112.menu.debug.l0=Level 0 (Release) +ninab112.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +ninab112.menu.debug.l1=Level 1 (Error Message) +ninab112.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +ninab112.menu.debug.l2=Level 2 (Full Debug) +ninab112.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +ninab112.menu.debug.l3=Level 3 (Segger SystemView) +ninab112.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +ninab112.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.19.0/cores/nRF5/Udp.h b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/cores/nRF5/Udp.h new file mode 100644 index 0000000..016042a --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/cores/nRF5/Udp.h @@ -0,0 +1,92 @@ +/* + * Udp.cpp: Library to send/receive UDP packets. + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef udp_h +#define udp_h + +#include +#include + +class UDP : public Stream { + +public: + virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + + // KH, add virtual function to support Multicast, necessary for many services (MDNS, etc.) + virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure + + virtual void stop() =0; // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port) =0; + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port) =0; + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket() =0; + // Write a single byte into the packet + virtual size_t write(uint8_t) =0; + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size) =0; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket() =0; + // Number of bytes remaining in the current packet + virtual int available() =0; + // Read a single byte from the current packet + virtual int read() =0; + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len) =0; + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) =0; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek() =0; + virtual void flush() =0; // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() =0; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() =0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.19.0/platform.txt b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/platform.txt new file mode 100644 index 0000000..6c7ed43 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/platform.txt @@ -0,0 +1,164 @@ +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# Copyright (c) 2016 Sandeep Mistry All right reserved. +# Copyright (c) 2017 Adafruit Industries. All rights reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +name=Adafruit nRF52 Boards +version=0.20.5 + +# Compile variables +# ----------------- + +compiler.warning_flags=-w +compiler.warning_flags.none=-w +compiler.warning_flags.default= +compiler.warning_flags.more=-Wall +compiler.warning_flags.all=-Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wno-pointer-arith + +compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ +compiler.c.cmd=arm-none-eabi-gcc +compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD +# KH, Error here to use gcc, mjust use g++ +#compiler.c.elf.cmd=arm-none-eabi-gcc +compiler.c.elf.cmd=arm-none-eabi-g++ +compiler.c.elf.flags=-Ofast -Wl,--gc-sections -save-temps +compiler.S.cmd=arm-none-eabi-gcc +compiler.S.flags=-c -g -x assembler-with-cpp +compiler.cpp.cmd=arm-none-eabi-g++ +compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD +compiler.ar.cmd=arm-none-eabi-ar +compiler.ar.flags=rcs +compiler.objcopy.cmd=arm-none-eabi-objcopy +compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 +compiler.elf2bin.flags=-O binary +compiler.elf2bin.cmd=arm-none-eabi-objcopy +compiler.elf2hex.flags=-O ihex +compiler.elf2hex.cmd=arm-none-eabi-objcopy +compiler.ldflags=-mcpu={build.mcu} -mthumb {build.float_flags} -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align --specs=nano.specs --specs=nosys.specs +compiler.size.cmd=arm-none-eabi-size + +# this can be overriden in boards.txt +build.float_flags=-mfloat-abi=hard -mfpu=fpv4-sp-d16 -u _printf_float +build.debug_flags=-DCFG_DEBUG=0 +build.logger_flags=-DCFG_LOGGER=1 +build.sysview_flags=-DCFG_SYSVIEW=0 + +# common compiler for nrf +rtos.path={build.core.path}/freertos +nordic.path={build.core.path}/nordic + +# build.logger_flags and build.sysview_flags and intentionally empty, +# to allow modification via a user's own boards.local.txt or platform.local.txt files. +build.flags.nrf= -DSOFTDEVICE_PRESENT -DARDUINO_NRF52_ADAFRUIT -DNRF52_SERIES -DLFS_NAME_MAX=64 -Ofast {build.debug_flags} {build.logger_flags} {build.sysview_flags} "-I{build.core.path}/cmsis/Core/Include" "-I{nordic.path}" "-I{nordic.path}/nrfx" "-I{nordic.path}/nrfx/hal" "-I{nordic.path}/nrfx/mdk" "-I{nordic.path}/nrfx/soc" "-I{nordic.path}/nrfx/drivers/include" "-I{nordic.path}/nrfx/drivers/src" "-I{nordic.path}/softdevice/{build.sd_name}_nrf52_{build.sd_version}_API/include" "-I{rtos.path}/Source/include" "-I{rtos.path}/config" "-I{rtos.path}/portable/GCC/nrf52" "-I{rtos.path}/portable/CMSIS/nrf52" "-I{build.core.path}/sysview/SEGGER" "-I{build.core.path}/sysview/Config" "-I{build.core.path}/TinyUSB" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore/tinyusb/src" + +# usb flags +build.flags.usb= -DUSBCON -DUSE_TINYUSB -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' + +# These can be overridden in platform.local.txt +compiler.c.extra_flags= +compiler.c.elf.extra_flags= +compiler.cpp.extra_flags= +compiler.S.extra_flags= +compiler.ar.extra_flags= +compiler.elf2bin.extra_flags= +compiler.elf2hex.extra_flags= + + +# Compile patterns +# ---------------- + +## Compile c files +## KH Add -DBOARD_NAME="{build.board}" +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.c.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +##recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.c.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +## Compile c++ files +## KH Add -DBOARD_NAME="{build.board}" +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.cpp.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +##recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.cpp.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +## Compile S files +## KH Add -DBOARD_NAME="{build.board}" +recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +##recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +## Create archives +recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" + +## Combine gc-sections, archives, and objects +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-L{build.core.path}/linker" "-T{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} -Wl,--start-group -lm "{build.path}/{archive_file}" -Wl,--end-group + +## Create output (bin file) +#recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2bin.cmd}" {compiler.elf2bin.flags} {compiler.elf2bin.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" + +## Create output (hex file) +recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" + +## Create dfu package zip file +recipe.objcopy.zip.pattern="{tools.nrfutil.cmd}" dfu genpkg --dev-type 0x0052 --sd-req {build.sd_fwid} --application "{build.path}/{build.project_name}.hex" "{build.path}/{build.project_name}.zip" + +## Create uf2 file +#recipe.objcopy.uf2.pattern=python "{runtime.platform.path}/tools/uf2conv/uf2conv.py" -f 0xADA52840 -c -o "{build.path}/{build.project_name}.uf2" "{build.path}/{build.project_name}.hex" + +## Save bin +recipe.output.tmp_file_bin={build.project_name}.bin +recipe.output.save_file_bin={build.project_name}.save.bin + +## Save hex +recipe.output.tmp_file_hex={build.project_name}.hex +recipe.output.save_file_hexu={build.project_name}.save.hex + +## Compute size +recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" +recipe.size.regex=^(?:\.text|\.data|)\s+([0-9]+).* +recipe.size.regex.data=^(?:\.data|\.bss)\s+([0-9]+).* + +## Export Compiled Binary +recipe.output.tmp_file={build.project_name}.hex +recipe.output.save_file={build.project_name}.{build.variant}.hex + +#*************************************************** +# adafruit-nrfutil for uploading +# https://github.com/adafruit/Adafruit_nRF52_nrfutil +# pre-built binaries are provided for macos and windows +#*************************************************** +tools.nrfutil.cmd=adafruit-nrfutil +tools.nrfutil.cmd.windows={runtime.platform.path}/tools/adafruit-nrfutil/win32/adafruit-nrfutil.exe +tools.nrfutil.cmd.macosx={runtime.platform.path}/tools/adafruit-nrfutil/macos/adafruit-nrfutil + +tools.nrfutil.upload.params.verbose=--verbose +tools.nrfutil.upload.params.quiet= +tools.nrfutil.upload.pattern="{cmd}" {upload.verbose} dfu serial -pkg "{build.path}/{build.project_name}.zip" -p {serial.port} -b 115200 --singlebank + +#*************************************************** +# Burning bootloader with either jlink or nrfutil +#*************************************************** + +# Bootloader version +tools.bootburn.bootloader.file={runtime.platform.path}/bootloader/{build.variant}/{build.variant}_bootloader-0.3.2_{build.sd_name}_{build.sd_version} + +tools.bootburn.bootloader.params.verbose= +tools.bootburn.bootloader.params.quiet= +tools.bootburn.bootloader.pattern={program.burn_pattern} + +# erase flash page while programming +tools.bootburn.erase.params.verbose= +tools.bootburn.erase.params.quiet= +tools.bootburn.erase.pattern= + diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B112_ublox/pins_arduino.h b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B112_ublox/pins_arduino.h new file mode 100644 index 0000000..3ef4d4a --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B112_ublox/pins_arduino.h @@ -0,0 +1,17 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 +*/ + +// API compatibility +#include "variant.h" diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B112_ublox/variant.cpp b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B112_ublox/variant.cpp new file mode 100644 index 0000000..a68820c --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B112_ublox/variant.cpp @@ -0,0 +1,62 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ +// Thanks to great work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip). +// See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) + +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" +#include "nrf.h" + +const uint32_t g_ADigitalPinMap[] = { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31 + }; + diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B112_ublox/variant.h b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B112_ublox/variant.h new file mode 100644 index 0000000..42c7791 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B112_ublox/variant.h @@ -0,0 +1,173 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ + +#ifndef _VARIANT_NINA_B112_UBLOX_ +#define _VARIANT_NINA_B112_UBLOX_ + +#define NRF_CLOCK_LFCLKSRC {.source = NRF_CLOCK_LF_SRC_XTAL, \ + .rc_ctiv = 0, \ +.rc_temp_ctiv = 0, \ +.xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM} + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (32u) +#define NUM_DIGITAL_PINS (32u) +#define NUM_ANALOG_INPUTS (6u) +#define NUM_ANALOG_OUTPUTS (0u) + +// LEDs +#define PIN_LED LED1 +#define LED_BUILTIN PIN_LED + +//LEDs onboard +#define LED1 (8) // Red +#define LED2 (16) // Green/SW1 +#define LED3 (18) // Blue + +#define LED_STATE_ON 1 // State when LED is litted + +//Switch + +#define SW1 (16) +#define SW2 (30) + +// NFC +#define PIN_NFC_1 (9) // P0.9 +#define PIN_NFC_2 (10) // P0.10 + +/* + * Analog pins + */ +#define PIN_A0 (3) // P0.03 +#define PIN_A1 (2) // P0.02 +#define PIN_A2 (4) // P0.04 +#define PIN_A3 (30) // P0.30 +#define PIN_A4 (29) // P0.29 +#define PIN_A5 (28) // P0.28 + +static const uint8_t A0 = PIN_A0 ; +static const uint8_t A1 = PIN_A1 ; +static const uint8_t A2 = PIN_A2 ; +static const uint8_t A3 = PIN_A3 ; +static const uint8_t A4 = PIN_A4 ; +static const uint8_t A5 = PIN_A5 ; + +#define ADC_RESOLUTION 14 + +#define PIN_D0 (5) // P0.05 +#define PIN_D1 (6) // P0.06 +#define PIN_D2 (7) // P0.07 +#define PIN_D3 (31) // P0.31 +#define PIN_D4 (18) // P0.18 +#define PIN_D6 (9) // P0.09 +#define PIN_D7 (10) // P0.10 +#define PIN_D9 (8) // P0.8 +#define PIN_D10 (11) // P0.11 +#define PIN_D11 (13) // P0.13 +#define PIN_D12 (12) // P0.12 +#define PIN_D13 (14) // P0.14 +#define PIN_D14 (2) // P0.02 +#define PIN_D15 (3) // P0.03 + +static const uint8_t D0 = PIN_D0 ; +static const uint8_t D1 = PIN_D1 ; +static const uint8_t D2 = PIN_D2 ; +static const uint8_t D3 = PIN_D3 ; +static const uint8_t D4 = PIN_D4 ; +static const uint8_t D6 = PIN_D6 ; +static const uint8_t D7 = PIN_D7 ; +static const uint8_t D9 = PIN_D9 ; +static const uint8_t D10 = PIN_D10 ; +static const uint8_t D11 = PIN_D11 ; +static const uint8_t D12 = PIN_D12 ; +static const uint8_t D13 = PIN_D13 ; +static const uint8_t D14 = PIN_D14 ; +static const uint8_t D15 = PIN_D15 ; + +// Other pins +//static const uint8_t AREF = PIN_AREF; + +//#define PIN_AREF (24) +//#define PIN_VBAT PIN_A7 + +/* + * Serial interfaces + */ +//#define PIN_SERIAL_RX (8) //used for original Adafruit Bootloader +//#define PIN_SERIAL_TX (6) //used for original Adafruit Bootloader + +#define PIN_SERIAL_RX (5) // P0.05 +#define PIN_SERIAL_TX (6) // P0.06 +#define PIN_SERIAL_CTS (7) // P0.07 +#define PIN_SERIAL_RTS (31) // P0.31 +#define PIN_SERIAL_DTR (28) // P0.28 +#define PIN_SERIAL_DSR (29) // P0.29 + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (12) // P0.12 +#define PIN_SPI_MOSI (13) // P0.13 +#define PIN_SPI_SCK (14) // P0.14 + +static const uint8_t SS = 11 ; // P0.11 +static const uint8_t MOSI = PIN_SPI_MOSI ; +static const uint8_t MISO = PIN_SPI_MISO ; +static const uint8_t SCK = PIN_SPI_SCK ; + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (2) // P0.02 +#define PIN_WIRE_SCL (3) // P0.03 + +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; + + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + + +#endif //_VARIANT_NINA_B112_UBLOX_ diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B302_ublox/pins_arduino.h b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B302_ublox/pins_arduino.h new file mode 100644 index 0000000..3ef4d4a --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B302_ublox/pins_arduino.h @@ -0,0 +1,17 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 +*/ + +// API compatibility +#include "variant.h" diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B302_ublox/variant.cpp b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B302_ublox/variant.cpp new file mode 100644 index 0000000..b51ac2f --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B302_ublox/variant.cpp @@ -0,0 +1,109 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ +// Thanks to great work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip). +// See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) + +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" +#include "nrf.h" + +const uint32_t g_ADigitalPinMap[] = +{ + // D0 .. D13 + 29, // D0 is P0.29 (UART TX) + 45, // D1 is P1.13 (UART RX + 44, // D2 is P1.12 (NFC2) + 31, // D3 is P0.31 (LED1) + 13, // D4 is P0.13 (LED2) + 11, // D5 is P0.11 + 9, // D6 is P0.09 + 10, // D7 is P0.10 (Button) + 41, // D8 is P1.09 (NeoPixel) + 12, // D9 is P0.12 + 14, // D10 is P0.14 + 15, // D11 is P0.15 + 32, // D12 is P1.00 + 7, // D13 is P0.07 + + // D14 .. D21 (aka A0 .. A7) + 4, // D14 is P0.04 (A0) + 30, // D15 is P0.30 (A1) + 5, // D16 is P0.05 (A2) + 2, // D17 is P0.02 (A3) + 28, // D18 is P0.28 (A4) + 3, // D19 is P0.03 (A5) + 29, // D20 is P0.29 (A6, Battery) ???? + 31, // D21 is P0.31 (A7, ARef) ???? + + // D22 .. D23 (aka I2C pins) + 16, // D22 is P0.16 (SDA) + 24, // D23 is P0.24 (SCL) + + // D24 .. D26 (aka SPI pins) + 32, // D24 is P1.00 (SPI MISO) + 15, // D25 is P0.15 (SPI MOSI) + 7, // D26 is P0.07 (SPI SCK ) + + // QSPI pins (not exposed via any header / test point) + 19, // D27 is P0.19 (QSPI CLK) + 17, // D28 is P0.17 (QSPI CS) + 20, // D29 is P0.20 (QSPI Data 0) + 21, // D30 is P0.21 (QSPI Data 1) + 22, // D31 is P0.22 (QSPI Data 2) + 23, // D32 is P0.23 (QSPI Data 3) + + // The remaining NFC pin + 9, // D33 is P0.09 (NFC1, exposed only via test point on bottom of board) + + // Thus, there are 34 defined pins + + // The remaining pins are not usable: + // + // + // The following pins were never listed as they were considered unusable + // 0, // P0.00 is XL1 (attached to 32.768kHz crystal) + // 1, // P0.01 is XL2 (attached to 32.768kHz crystal) + // 18, // P0.18 is RESET (attached to switch) + // 32, // P1.00 is SWO (attached to debug header) + // + // The remaining pins are not connected (per schematic) + // 33, // P1.01 is not connected per schematic + // 35, // P1.03 is not connected per schematic + // 36, // P1.04 is not connected per schematic + // 37, // P1.05 is not connected per schematic + // 38, // P1.06 is not connected per schematic + // 39, // P1.07 is not connected per schematic + // 43, // P1.11 is not connected per schematic + // 44, // P1.12 is not connected per schematic + // 45, // P1.13 is not connected per schematic + // 46, // P1.14 is not connected per schematic +}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); +} + diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B302_ublox/variant.h b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B302_ublox/variant.h new file mode 100644 index 0000000..a5b7eb9 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.19.0/variants/NINA_B302_ublox/variant.h @@ -0,0 +1,159 @@ + /* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ + +// Thanks to great work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip). +// See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) + +#ifndef _VARIANT_NINA_B302_UBLOX_ +#define _VARIANT_NINA_B302_UBLOX_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus +// (XX) = TABLE INDEX +// Number of pins defined in PinDescription array +#define PINS_COUNT (34) +#define NUM_DIGITAL_PINS (34) +#define NUM_ANALOG_INPUTS (6) // A6 is used for battery, A7 is analog reference +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (3) +#define PIN_LED2 (4) +#define PIN_NEOPIXEL (8) + +#define LED_BUILTIN PIN_LED1 +#define LED_CONN PIN_LED2 + +#define LED_RED PIN_LED1 +#define LED_BLUE PIN_LED2 + +#define LED_STATE_ON 1 // State when LED is litted + +/* + * Buttons + */ +#define PIN_BUTTON1 (7) + +/* + * Analog pins + */ +#define PIN_A0 (14) +#define PIN_A1 (15) +#define PIN_A2 (16) +#define PIN_A3 (17) +#define PIN_A4 (18) +#define PIN_A5 (19) +#define PIN_A6 (20) +#define PIN_A7 (21) + +#define D0 (0) +#define D1 (1) +#define D2 (2) +#define D3 (3) +#define D4 (4) +#define D5 (5) +#define D6 (6) +#define D7 (7) +#define D8 (8) +#define D9 (9) +#define D10 (10) +#define D11 (11) +#define D12 (12) +#define D13 (13) + +static const uint8_t A0 = PIN_A0 ; +static const uint8_t A1 = PIN_A1 ; +static const uint8_t A2 = PIN_A2 ; +static const uint8_t A3 = PIN_A3 ; +static const uint8_t A4 = PIN_A4 ; +static const uint8_t A5 = PIN_A5 ; +static const uint8_t A6 = PIN_A6 ; +static const uint8_t A7 = PIN_A7 ; +#define ADC_RESOLUTION 14 + +// Other pins +#define PIN_AREF PIN_A7 +#define PIN_VBAT PIN_A6 +#define PIN_NFC1 (33) +#define PIN_NFC2 (2) + +static const uint8_t AREF = PIN_AREF; + +/* + * Serial interfaces + */ +#define PIN_SERIAL1_RX (1) +#define PIN_SERIAL1_TX (0) + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (24) //24 original +#define PIN_SPI_MOSI (25) //25 original +#define PIN_SPI_SCK (26) //26 original + +static const uint8_t SS = (13); +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (22) +#define PIN_WIRE_SCL (23) + +// QSPI Pins +#define PIN_QSPI_SCK 27 +#define PIN_QSPI_CS 28 +#define PIN_QSPI_IO0 29 +#define PIN_QSPI_IO1 30 +#define PIN_QSPI_IO2 31 +#define PIN_QSPI_IO3 32 + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES GD25Q16C +#define EXTERNAL_FLASH_USE_QSPI + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif //_VARIANT_NINA_B302_UBLOX_ diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.1/boards.txt b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/boards.txt new file mode 100644 index 0000000..bbe9f9e --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/boards.txt @@ -0,0 +1,649 @@ +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# Copyright (c) 2016 Sandeep Mistry All right reserved. +# Copyright (c) 2017 Adafruit Industries. 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 + +menu.softdevice=Bootloader +menu.debug=Debug + +# ---------------------------------- +# Bluefruit Feather nRF52832 +# ---------------------------------- +feather52832.name=Adafruit Feather nRF52832 +feather52832.bootloader.tool=bootburn + +# Upload +feather52832.upload.tool=nrfutil +feather52832.upload.protocol=nrfutil +feather52832.upload.use_1200bps_touch=false +feather52832.upload.wait_for_upload_port=false +feather52832.upload.native_usb=false +feather52832.upload.maximum_size=290816 +feather52832.upload.maximum_data_size=52224 + +# Build +feather52832.build.mcu=cortex-m4 +feather52832.build.f_cpu=64000000 +feather52832.build.board=NRF52832_FEATHER +feather52832.build.core=nRF5 +feather52832.build.variant=feather_nrf52832 +feather52840.build.usb_manufacturer="Adafruit LLC" +feather52840.build.usb_product="Feather nRF52832" +feather52832.build.extra_flags=-DNRF52832_XXAA -DNRF52832_FEATHER -DNRF52 +feather52832.build.ldscript=nrf52832_s132_v6.ld + +# SofDevice Menu +feather52832.menu.softdevice.s132v6=0.3.2 SoftDevice s132 6.1.1 +feather52832.menu.softdevice.s132v6.build.sd_name=s132 +feather52832.menu.softdevice.s132v6.build.sd_version=6.1.1 +feather52832.menu.softdevice.s132v6.build.sd_fwid=0x00B7 + +# Debug Menu +feather52832.menu.debug.l0=Level 0 (Release) +feather52832.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +feather52832.menu.debug.l1=Level 1 (Error Message) +feather52832.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +feather52832.menu.debug.l2=Level 2 (Full Debug) +feather52832.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +feather52832.menu.debug.l3=Level 3 (Segger SystemView) +feather52832.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +feather52832.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Bluefruit Feather nRF52840 Express +# ---------------------------------- +feather52840.name=Adafruit Feather nRF52840 Express + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +feather52840.vid.0=0x239A +feather52840.pid.0=0x8029 +feather52840.vid.1=0x239A +feather52840.pid.1=0x0029 +feather52840.vid.2=0x239A +feather52840.pid.2=0x002A +feather52840.vid.3=0x239A +feather52840.pid.3=0x802A + +# Upload +feather52840.bootloader.tool=bootburn +feather52840.upload.tool=nrfutil +feather52840.upload.protocol=nrfutil +feather52840.upload.use_1200bps_touch=true +feather52840.upload.wait_for_upload_port=true +feather52840.upload.maximum_size=815104 +feather52840.upload.maximum_data_size=237568 + +# Build +feather52840.build.mcu=cortex-m4 +feather52840.build.f_cpu=64000000 +feather52840.build.board=NRF52840_FEATHER +feather52840.build.core=nRF5 +feather52840.build.variant=feather_nrf52840_express +feather52840.build.usb_manufacturer="Adafruit LLC" +feather52840.build.usb_product="Feather nRF52840 Express" +feather52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_FEATHER {build.flags.usb} +feather52840.build.ldscript=nrf52840_s140_v6.ld +feather52840.build.vid=0x239A +feather52840.build.pid=0x8029 + +# SofDevice Menu +feather52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +feather52840.menu.softdevice.s140v6.build.sd_name=s140 +feather52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +feather52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +feather52840.menu.debug.l0=Level 0 (Release) +feather52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +feather52840.menu.debug.l1=Level 1 (Error Message) +feather52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +feather52840.menu.debug.l2=Level 2 (Full Debug) +feather52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +feather52840.menu.debug.l3=Level 3 (Segger SystemView) +feather52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +feather52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + +# ---------------------------------- +# Feather Bluefruit sense +# ---------------------------------- +feather52840sense.name=Adafruit Feather Bluefruit Sense + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +feather52840sense.vid.0=0x239A +feather52840sense.pid.0=0x8087 +feather52840sense.vid.1=0x239A +feather52840sense.pid.1=0x0087 +feather52840sense.vid.2=0x239A +feather52840sense.pid.2=0x0088 +feather52840sense.vid.3=0x239A +feather52840sense.pid.3=0x8088 + +# Upload +feather52840sense.bootloader.tool=bootburn +feather52840sense.upload.tool=nrfutil +feather52840sense.upload.protocol=nrfutil +feather52840sense.upload.use_1200bps_touch=true +feather52840sense.upload.wait_for_upload_port=true +feather52840sense.upload.maximum_size=815104 +feather52840sense.upload.maximum_data_size=237568 + +# Build +feather52840sense.build.mcu=cortex-m4 +feather52840sense.build.f_cpu=64000000 +feather52840sense.build.board=NRF52840_FEATHER_SENSE +feather52840sense.build.core=nRF5 +feather52840sense.build.variant=feather_nrf52840_sense +feather52840sense.build.usb_manufacturer="Adafruit LLC" +feather52840sense.build.usb_product="Feather nRF52840 Sense" +feather52840sense.build.extra_flags=-DNRF52840_XXAA -DNRF52840_FEATHER_SENSE {build.flags.usb} +feather52840sense.build.ldscript=nrf52840_s140_v6.ld +feather52840sense.build.vid=0x239A +feather52840sense.build.pid=0x8087 + +# SofDevice Menu +feather52840sense.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +feather52840sense.menu.softdevice.s140v6.build.sd_name=s140 +feather52840sense.menu.softdevice.s140v6.build.sd_version=6.1.1 +feather52840sense.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +feather52840sense.menu.debug.l0=Level 0 (Release) +feather52840sense.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +feather52840sense.menu.debug.l1=Level 1 (Error Message) +feather52840sense.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +feather52840sense.menu.debug.l2=Level 2 (Full Debug) +feather52840sense.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +feather52840sense.menu.debug.l3=Level 3 (Segger SystemView) +feather52840sense.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +feather52840sense.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + +# --------------------------------------------- +# Bluefruit ItsyBitsy nRF52840 Express +# --------------------------------------------- +itsybitsy52840.name=Adafruit ItsyBitsy nRF52840 Express + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +itsybitsy52840.vid.0=0x239A +itsybitsy52840.pid.0=0x8051 +itsybitsy52840.vid.1=0x239A +itsybitsy52840.pid.1=0x0051 +itsybitsy52840.vid.2=0x239A +itsybitsy52840.pid.2=0x0052 +itsybitsy52840.vid.3=0x239A +itsybitsy52840.pid.3=0x8052 + +# Upload +itsybitsy52840.bootloader.tool=bootburn +itsybitsy52840.upload.tool=nrfutil +itsybitsy52840.upload.protocol=nrfutil +itsybitsy52840.upload.use_1200bps_touch=true +itsybitsy52840.upload.wait_for_upload_port=true +itsybitsy52840.upload.maximum_size=815104 +itsybitsy52840.upload.maximum_data_size=237568 + +# Build +itsybitsy52840.build.mcu=cortex-m4 +itsybitsy52840.build.f_cpu=64000000 +itsybitsy52840.build.board=NRF52840_ITSYBITSY +itsybitsy52840.build.core=nRF5 +itsybitsy52840.build.variant=itsybitsy_nrf52840_express +itsybitsy52840.build.usb_manufacturer="Adafruit LLC" +itsybitsy52840.build.usb_product="ItsyBitsy nRF52840 Express" +itsybitsy52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_ITSYBITSY -DARDUINO_NRF52_ITSYBITSY {build.flags.usb} +itsybitsy52840.build.ldscript=nrf52840_s140_v6.ld +itsybitsy52840.build.vid=0x239A +itsybitsy52840.build.pid=0x8051 + +# SofDevice Menu +itsybitsy52840.menu.softdevice.s140v6=0.2.11 SoftDevice s140 6.1.1 +itsybitsy52840.menu.softdevice.s140v6.build.sd_name=s140 +itsybitsy52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +itsybitsy52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +itsybitsy52840.menu.debug.l0=Level 0 (Release) +itsybitsy52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +itsybitsy52840.menu.debug.l1=Level 1 (Error Message) +itsybitsy52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +itsybitsy52840.menu.debug.l2=Level 2 (Full Debug) +itsybitsy52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +itsybitsy52840.menu.debug.l3=Level 3 (Segger SystemView) +itsybitsy52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +itsybitsy52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# --------------------------------------------- +# Bluefruit Circuit Playground nRF52840 Express +# --------------------------------------------- +cplaynrf52840.name=Adafruit Circuit Playground Bluefruit + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +cplaynrf52840.vid.0=0x239A +cplaynrf52840.pid.0=0x8045 +cplaynrf52840.vid.1=0x239A +cplaynrf52840.pid.1=0x0045 +cplaynrf52840.vid.2=0x239A +cplaynrf52840.pid.2=0x0046 +cplaynrf52840.vid.3=0x239A +cplaynrf52840.pid.3=0x8046 + +# Upload +cplaynrf52840.bootloader.tool=bootburn +cplaynrf52840.upload.tool=nrfutil +cplaynrf52840.upload.protocol=nrfutil +cplaynrf52840.upload.use_1200bps_touch=true +cplaynrf52840.upload.wait_for_upload_port=true +cplaynrf52840.upload.maximum_size=815104 +cplaynrf52840.upload.maximum_data_size=237568 + +# Build +cplaynrf52840.build.mcu=cortex-m4 +cplaynrf52840.build.f_cpu=64000000 +cplaynrf52840.build.board=NRF52840_CIRCUITPLAY +cplaynrf52840.build.core=nRF5 +cplaynrf52840.build.variant=circuitplayground_nrf52840 +cplaynrf52840.build.usb_manufacturer="Adafruit LLC" +cplaynrf52840.build.usb_product="Circuit Playground Bluefruit" +cplaynrf52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_CIRCUITPLAY {build.flags.usb} +cplaynrf52840.build.ldscript=nrf52840_s140_v6.ld +cplaynrf52840.build.vid=0x239A +cplaynrf52840.build.pid=0x8045 + +# SofDevice Menu +cplaynrf52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +cplaynrf52840.menu.softdevice.s140v6.build.sd_name=s140 +cplaynrf52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +cplaynrf52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +cplaynrf52840.menu.debug.l0=Level 0 (Release) +cplaynrf52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +cplaynrf52840.menu.debug.l1=Level 1 (Error Message) +cplaynrf52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +cplaynrf52840.menu.debug.l2=Level 2 (Full Debug) +cplaynrf52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +cplaynrf52840.menu.debug.l3=Level 3 (Segger SystemView) +cplaynrf52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +cplaynrf52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + +# --------------------------------------------- +# Clue nRF52840 +# --------------------------------------------- +cluenrf52840.name=Adafruit CLUE + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +cluenrf52840.vid.0=0x239A +cluenrf52840.pid.0=0x8072 +cluenrf52840.vid.1=0x239A +cluenrf52840.pid.1=0x0072 +cluenrf52840.vid.2=0x239A +cluenrf52840.pid.2=0x0071 +cluenrf52840.vid.3=0x239A +cluenrf52840.pid.3=0x8071 + +# Upload +cluenrf52840.bootloader.tool=bootburn +cluenrf52840.upload.tool=nrfutil +cluenrf52840.upload.protocol=nrfutil +cluenrf52840.upload.use_1200bps_touch=true +cluenrf52840.upload.wait_for_upload_port=true +cluenrf52840.upload.maximum_size=815104 +cluenrf52840.upload.maximum_data_size=237568 + +# Build +cluenrf52840.build.mcu=cortex-m4 +cluenrf52840.build.f_cpu=64000000 +cluenrf52840.build.board=NRF52840_CLUE +cluenrf52840.build.core=nRF5 +cluenrf52840.build.variant=clue_nrf52840 +cluenrf52840.build.usb_manufacturer="Adafruit LLC" +cluenrf52840.build.usb_product="CLUE" +cluenrf52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_CLUE {build.flags.usb} +cluenrf52840.build.ldscript=nrf52840_s140_v6.ld +cluenrf52840.build.vid=0x239A +cluenrf52840.build.pid=0x8071 + +# SofDevice Menu +cluenrf52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +cluenrf52840.menu.softdevice.s140v6.build.sd_name=s140 +cluenrf52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +cluenrf52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +cluenrf52840.menu.debug.l0=Level 0 (Release) +cluenrf52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +cluenrf52840.menu.debug.l1=Level 1 (Error Message) +cluenrf52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +cluenrf52840.menu.debug.l2=Level 2 (Full Debug) +cluenrf52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +cluenrf52840.menu.debug.l3=Level 3 (Segger SystemView) +cluenrf52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +cluenrf52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Bluefruit Metro nRF52840 Express +# ---------------------------------- +metro52840.name=Adafruit Bluefruit Metro nRF52840 Express + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +metro52840.vid.0=0x239A +metro52840.pid.0=0x803F +metro52840.vid.1=0x239A +metro52840.pid.1=0x003F +metro52840.vid.2=0x239A +metro52840.pid.2=0x0040 +metro52840.vid.3=0x239A +metro52840.pid.3=0x8040 + +# Upload +metro52840.bootloader.tool=bootburn +metro52840.upload.tool=nrfutil +metro52840.upload.protocol=nrfutil +metro52840.upload.use_1200bps_touch=true +metro52840.upload.wait_for_upload_port=true +metro52840.upload.maximum_size=815104 +metro52840.upload.maximum_data_size=237568 + +# Build +metro52840.build.mcu=cortex-m4 +metro52840.build.f_cpu=64000000 +metro52840.build.board=NRF52840_METRO +metro52840.build.core=nRF5 +metro52840.build.variant=metro_nrf52840_express +metro52840.build.usb_manufacturer="Adafruit LLC" +metro52840.build.usb_product="Metro nRF52840 Express" +metro52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_METRO {build.flags.usb} +metro52840.build.ldscript=nrf52840_s140_v6.ld +metro52840.build.vid=0x239A +metro52840.build.pid=0x803F + +# SofDevice Menu +metro52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +metro52840.menu.softdevice.s140v6.build.sd_name=s140 +metro52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +metro52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +metro52840.menu.debug.l0=Level 0 (Release) +metro52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +metro52840.menu.debug.l1=Level 1 (Error Message) +metro52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +metro52840.menu.debug.l2=Level 2 (Full Debug) +metro52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +metro52840.menu.debug.l3=Level 3 (Segger SystemView) +metro52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +metro52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + + + +# ------------------------------------------------------- +# +# Boards that aren't made by Adafruit +# +# ------------------------------------------------------- + + +# ---------------------------------- +# Nordic nRF52840DK (PCA10056) +# ---------------------------------- +pca10056.name=Nordic nRF52840DK (PCA10056) +pca10056.bootloader.tool=bootburn + +# Upload +pca10056.upload.tool=nrfutil +pca10056.upload.protocol=nrfutil +pca10056.upload.use_1200bps_touch=true +pca10056.upload.wait_for_upload_port=true +pca10056.upload.maximum_size=815104 +pca10056.upload.maximum_data_size=237568 + +# Build +pca10056.build.mcu=cortex-m4 +pca10056.build.f_cpu=64000000 +pca10056.build.board=NRF52840_PCA10056 +pca10056.build.core=nRF5 +pca10056.build.variant=pca10056 +pca10056.build.usb_manufacturer="Nordic" +pca10056.build.usb_product="nRF52840 DK" +pca10056.build.extra_flags=-DNRF52840_XXAA -DNRF52840_PCA10056 {build.flags.usb} +pca10056.build.ldscript=nrf52840_s140_v6.ld +pca10056.build.vid=0x239A +pca10056.build.pid=0x8029 + +# SofDevice Menu +pca10056.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +pca10056.menu.softdevice.s140v6.build.sd_name=s140 +pca10056.menu.softdevice.s140v6.build.sd_version=6.1.1 +pca10056.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +pca10056.menu.debug.l0=Level 0 (Release) +pca10056.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +pca10056.menu.debug.l1=Level 1 (Error Message) +pca10056.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +pca10056.menu.debug.l2=Level 2 (Full Debug) +pca10056.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +pca10056.menu.debug.l3=Level 3 (Segger SystemView) +pca10056.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +pca10056.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Particle Xenon +# ---------------------------------- +particle_xenon.name=Particle Xenon + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +particle_xenon.vid.0=0x239A +particle_xenon.pid.0=0x8029 +particle_xenon.vid.1=0x239A +particle_xenon.pid.1=0x0029 +particle_xenon.vid.2=0x239A +particle_xenon.pid.2=0x002A +particle_xenon.vid.3=0x239A +particle_xenon.pid.3=0x802A + +# Upload +particle_xenon.bootloader.tool=bootburn +particle_xenon.upload.tool=nrfutil +particle_xenon.upload.protocol=nrfutil +particle_xenon.upload.use_1200bps_touch=true +particle_xenon.upload.wait_for_upload_port=true +particle_xenon.upload.maximum_size=815104 +particle_xenon.upload.maximum_data_size=237568 + +# Build +particle_xenon.build.mcu=cortex-m4 +particle_xenon.build.f_cpu=64000000 +particle_xenon.build.board=PARTICLE_XENON +particle_xenon.build.core=nRF5 +particle_xenon.build.variant=particle_xenon +particle_xenon.build.usb_manufacturer="Particle Industries" +particle_xenon.build.usb_product="Particle Xenon" +particle_xenon.build.extra_flags=-DNRF52840_XXAA -DPARTICLE_XENON {build.flags.usb} +particle_xenon.build.ldscript=nrf52840_s140_v6.ld +particle_xenon.build.vid=0x239A +particle_xenon.build.pid=0x8029 + +# SofDevice Menu +particle_xenon.menu.softdevice.s140v6=0.2.11 SoftDevice s140 6.1.1 +particle_xenon.menu.softdevice.s140v6.build.sd_name=s140 +particle_xenon.menu.softdevice.s140v6.build.sd_version=6.1.1 +particle_xenon.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +particle_xenon.menu.debug.l0=Level 0 (Release) +particle_xenon.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +particle_xenon.menu.debug.l1=Level 1 (Error Message) +particle_xenon.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +particle_xenon.menu.debug.l2=Level 2 (Full Debug) +particle_xenon.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +particle_xenon.menu.debug.l3=Level 3 (Segger SystemView) +particle_xenon.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +particle_xenon.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Raytac MDBT50Q - RX +# ---------------------------------- +mdbt50qrx.name=Raytac MDBT50Q-RX Dongle + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +mdbt50qrx.vid.0=0x239A +mdbt50qrx.pid.0=0x8029 +mdbt50qrx.vid.1=0x239A +mdbt50qrx.pid.1=0x0029 +mdbt50qrx.vid.2=0x239A +mdbt50qrx.pid.2=0x002A +mdbt50qrx.vid.3=0x239A +mdbt50qrx.pid.3=0x802A + +# Upload +mdbt50qrx.bootloader.tool=bootburn +mdbt50qrx.upload.tool=nrfutil +mdbt50qrx.upload.protocol=nrfutil +mdbt50qrx.upload.use_1200bps_touch=true +mdbt50qrx.upload.wait_for_upload_port=true +mdbt50qrx.upload.maximum_size=815104 +mdbt50qrx.upload.maximum_data_size=237568 + +# Build +mdbt50qrx.build.mcu=cortex-m4 +mdbt50qrx.build.f_cpu=64000000 +mdbt50qrx.build.board=MDBT50Q_RX +mdbt50qrx.build.core=nRF5 +mdbt50qrx.build.variant=raytac_mdbt50q_rx +mdbt50qrx.build.usb_manufacturer="Raytac Corporation" +mdbt50qrx.build.usb_product="Raytac MDBT50Q - RX" +mdbt50qrx.build.extra_flags=-DNRF52840_XXAA -DMDBT50Q_RX {build.flags.usb} +mdbt50qrx.build.ldscript=nrf52840_s140_v6.ld +mdbt50qrx.build.vid=0x239A +mdbt50qrx.build.pid=0x8029 + +# SofDevice Menu +mdbt50qrx.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +mdbt50qrx.menu.softdevice.s140v6.build.sd_name=s140 +mdbt50qrx.menu.softdevice.s140v6.build.sd_version=6.1.1 +mdbt50qrx.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +mdbt50qrx.menu.debug.l0=Level 0 (Release) +mdbt50qrx.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +mdbt50qrx.menu.debug.l1=Level 1 (Error Message) +mdbt50qrx.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +mdbt50qrx.menu.debug.l2=Level 2 (Full Debug) +mdbt50qrx.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +mdbt50qrx.menu.debug.l3=Level 3 (Segger SystemView) +mdbt50qrx.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +mdbt50qrx.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# NINA B302 +# ---------------------------------- +ninab302.name=NINA B302 ublox + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +ninab302.vid.0=0x239A +ninab302.pid.0=0x8029 +ninab302.vid.1=0x239A +ninab302.pid.1=0x0029 +ninab302.vid.2=0x7239A +ninab302.pid.2=0x002A +ninab302.vid.3=0x239A +ninab302.pid.3=0x802A + +# Upload +ninab302.bootloader.tool=bootburn +ninab302.upload.tool=nrfutil +ninab302.upload.protocol=nrfutil +ninab302.upload.use_1200bps_touch=true +ninab302.upload.wait_for_upload_port=true +ninab302.upload.maximum_size=815104 +ninab302.upload.maximum_data_size=237568 + +# Build +ninab302.build.mcu=cortex-m4 +ninab302.build.f_cpu=64000000 +ninab302.build.board=NINA_B302_ublox +ninab302.build.core=nRF5 +ninab302.build.variant=NINA_B302_ublox +ninab302.build.usb_manufacturer="Nordic" +ninab302.build.usb_product="NINA B302 ublox" +ninab302.build.extra_flags=-DNRF52840_XXAA -DNINA_B302_ublox {build.flags.usb} +ninab302.build.ldscript=nrf52840_s140_v6.ld +ninab302.build.vid=0x239A +ninab302.build.pid=0x8029 + +# SofDevice Menu +ninab302.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +ninab302.menu.softdevice.s140v6.build.sd_name=s140 +ninab302.menu.softdevice.s140v6.build.sd_version=6.1.1 +ninab302.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +ninab302.menu.debug.l0=Level 0 (Release) +ninab302.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +ninab302.menu.debug.l1=Level 1 (Error Message) +ninab302.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +ninab302.menu.debug.l2=Level 2 (Full Debug) +ninab302.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +ninab302.menu.debug.l3=Level 3 (Segger SystemView) +ninab302.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +ninab302.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# NINA B112 +# ---------------------------------- +ninab112.name=NINA B112 ublox +ninab112.bootloader.tool=bootburn + +# Upload +ninab112.upload.tool=nrfutil +ninab112.upload.protocol=nrfutil +ninab112.upload.use_1200bps_touch=false +ninab112.upload.wait_for_upload_port=false +ninab112.upload.native_usb=false +ninab112.upload.maximum_size=290816 +ninab112.upload.maximum_data_size=52224 + +# Build +ninab112.build.mcu=cortex-m4 +ninab112.build.f_cpu=64000000 +ninab112.build.board=NINA_B112_ublox +ninab112.build.core=nRF5 +ninab112.build.variant=NINA_B112_ublox +feather52840.build.usb_manufacturer="Adafruit LLC" +feather52840.build.usb_product="Feather nRF52832" +ninab112.build.extra_flags=-DNRF52832_XXAA -DNINA_B112_ublox -DNRF52 +ninab112.build.ldscript=nrf52832_s132_v6.ld + +# SofDevice Menu +ninab112.menu.softdevice.s132v6=0.3.2 SoftDevice s132 6.1.1 +ninab112.menu.softdevice.s132v6.build.sd_name=s132 +ninab112.menu.softdevice.s132v6.build.sd_version=6.1.1 +ninab112.menu.softdevice.s132v6.build.sd_fwid=0x00B7 + +# Debug Menu +ninab112.menu.debug.l0=Level 0 (Release) +ninab112.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +ninab112.menu.debug.l1=Level 1 (Error Message) +ninab112.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +ninab112.menu.debug.l2=Level 2 (Full Debug) +ninab112.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +ninab112.menu.debug.l3=Level 3 (Segger SystemView) +ninab112.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +ninab112.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.1/cores/nRF5/Udp.h b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/cores/nRF5/Udp.h new file mode 100644 index 0000000..016042a --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/cores/nRF5/Udp.h @@ -0,0 +1,92 @@ +/* + * Udp.cpp: Library to send/receive UDP packets. + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef udp_h +#define udp_h + +#include +#include + +class UDP : public Stream { + +public: + virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + + // KH, add virtual function to support Multicast, necessary for many services (MDNS, etc.) + virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure + + virtual void stop() =0; // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port) =0; + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port) =0; + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket() =0; + // Write a single byte into the packet + virtual size_t write(uint8_t) =0; + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size) =0; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket() =0; + // Number of bytes remaining in the current packet + virtual int available() =0; + // Read a single byte from the current packet + virtual int read() =0; + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len) =0; + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) =0; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek() =0; + virtual void flush() =0; // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() =0; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() =0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.1/platform.txt b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/platform.txt new file mode 100644 index 0000000..6c7ed43 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/platform.txt @@ -0,0 +1,164 @@ +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# Copyright (c) 2016 Sandeep Mistry All right reserved. +# Copyright (c) 2017 Adafruit Industries. All rights reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +name=Adafruit nRF52 Boards +version=0.20.5 + +# Compile variables +# ----------------- + +compiler.warning_flags=-w +compiler.warning_flags.none=-w +compiler.warning_flags.default= +compiler.warning_flags.more=-Wall +compiler.warning_flags.all=-Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wno-pointer-arith + +compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ +compiler.c.cmd=arm-none-eabi-gcc +compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD +# KH, Error here to use gcc, mjust use g++ +#compiler.c.elf.cmd=arm-none-eabi-gcc +compiler.c.elf.cmd=arm-none-eabi-g++ +compiler.c.elf.flags=-Ofast -Wl,--gc-sections -save-temps +compiler.S.cmd=arm-none-eabi-gcc +compiler.S.flags=-c -g -x assembler-with-cpp +compiler.cpp.cmd=arm-none-eabi-g++ +compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD +compiler.ar.cmd=arm-none-eabi-ar +compiler.ar.flags=rcs +compiler.objcopy.cmd=arm-none-eabi-objcopy +compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 +compiler.elf2bin.flags=-O binary +compiler.elf2bin.cmd=arm-none-eabi-objcopy +compiler.elf2hex.flags=-O ihex +compiler.elf2hex.cmd=arm-none-eabi-objcopy +compiler.ldflags=-mcpu={build.mcu} -mthumb {build.float_flags} -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align --specs=nano.specs --specs=nosys.specs +compiler.size.cmd=arm-none-eabi-size + +# this can be overriden in boards.txt +build.float_flags=-mfloat-abi=hard -mfpu=fpv4-sp-d16 -u _printf_float +build.debug_flags=-DCFG_DEBUG=0 +build.logger_flags=-DCFG_LOGGER=1 +build.sysview_flags=-DCFG_SYSVIEW=0 + +# common compiler for nrf +rtos.path={build.core.path}/freertos +nordic.path={build.core.path}/nordic + +# build.logger_flags and build.sysview_flags and intentionally empty, +# to allow modification via a user's own boards.local.txt or platform.local.txt files. +build.flags.nrf= -DSOFTDEVICE_PRESENT -DARDUINO_NRF52_ADAFRUIT -DNRF52_SERIES -DLFS_NAME_MAX=64 -Ofast {build.debug_flags} {build.logger_flags} {build.sysview_flags} "-I{build.core.path}/cmsis/Core/Include" "-I{nordic.path}" "-I{nordic.path}/nrfx" "-I{nordic.path}/nrfx/hal" "-I{nordic.path}/nrfx/mdk" "-I{nordic.path}/nrfx/soc" "-I{nordic.path}/nrfx/drivers/include" "-I{nordic.path}/nrfx/drivers/src" "-I{nordic.path}/softdevice/{build.sd_name}_nrf52_{build.sd_version}_API/include" "-I{rtos.path}/Source/include" "-I{rtos.path}/config" "-I{rtos.path}/portable/GCC/nrf52" "-I{rtos.path}/portable/CMSIS/nrf52" "-I{build.core.path}/sysview/SEGGER" "-I{build.core.path}/sysview/Config" "-I{build.core.path}/TinyUSB" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore/tinyusb/src" + +# usb flags +build.flags.usb= -DUSBCON -DUSE_TINYUSB -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' + +# These can be overridden in platform.local.txt +compiler.c.extra_flags= +compiler.c.elf.extra_flags= +compiler.cpp.extra_flags= +compiler.S.extra_flags= +compiler.ar.extra_flags= +compiler.elf2bin.extra_flags= +compiler.elf2hex.extra_flags= + + +# Compile patterns +# ---------------- + +## Compile c files +## KH Add -DBOARD_NAME="{build.board}" +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.c.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +##recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.c.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +## Compile c++ files +## KH Add -DBOARD_NAME="{build.board}" +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.cpp.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +##recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.cpp.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +## Compile S files +## KH Add -DBOARD_NAME="{build.board}" +recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +##recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +## Create archives +recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" + +## Combine gc-sections, archives, and objects +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-L{build.core.path}/linker" "-T{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} -Wl,--start-group -lm "{build.path}/{archive_file}" -Wl,--end-group + +## Create output (bin file) +#recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2bin.cmd}" {compiler.elf2bin.flags} {compiler.elf2bin.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" + +## Create output (hex file) +recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" + +## Create dfu package zip file +recipe.objcopy.zip.pattern="{tools.nrfutil.cmd}" dfu genpkg --dev-type 0x0052 --sd-req {build.sd_fwid} --application "{build.path}/{build.project_name}.hex" "{build.path}/{build.project_name}.zip" + +## Create uf2 file +#recipe.objcopy.uf2.pattern=python "{runtime.platform.path}/tools/uf2conv/uf2conv.py" -f 0xADA52840 -c -o "{build.path}/{build.project_name}.uf2" "{build.path}/{build.project_name}.hex" + +## Save bin +recipe.output.tmp_file_bin={build.project_name}.bin +recipe.output.save_file_bin={build.project_name}.save.bin + +## Save hex +recipe.output.tmp_file_hex={build.project_name}.hex +recipe.output.save_file_hexu={build.project_name}.save.hex + +## Compute size +recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" +recipe.size.regex=^(?:\.text|\.data|)\s+([0-9]+).* +recipe.size.regex.data=^(?:\.data|\.bss)\s+([0-9]+).* + +## Export Compiled Binary +recipe.output.tmp_file={build.project_name}.hex +recipe.output.save_file={build.project_name}.{build.variant}.hex + +#*************************************************** +# adafruit-nrfutil for uploading +# https://github.com/adafruit/Adafruit_nRF52_nrfutil +# pre-built binaries are provided for macos and windows +#*************************************************** +tools.nrfutil.cmd=adafruit-nrfutil +tools.nrfutil.cmd.windows={runtime.platform.path}/tools/adafruit-nrfutil/win32/adafruit-nrfutil.exe +tools.nrfutil.cmd.macosx={runtime.platform.path}/tools/adafruit-nrfutil/macos/adafruit-nrfutil + +tools.nrfutil.upload.params.verbose=--verbose +tools.nrfutil.upload.params.quiet= +tools.nrfutil.upload.pattern="{cmd}" {upload.verbose} dfu serial -pkg "{build.path}/{build.project_name}.zip" -p {serial.port} -b 115200 --singlebank + +#*************************************************** +# Burning bootloader with either jlink or nrfutil +#*************************************************** + +# Bootloader version +tools.bootburn.bootloader.file={runtime.platform.path}/bootloader/{build.variant}/{build.variant}_bootloader-0.3.2_{build.sd_name}_{build.sd_version} + +tools.bootburn.bootloader.params.verbose= +tools.bootburn.bootloader.params.quiet= +tools.bootburn.bootloader.pattern={program.burn_pattern} + +# erase flash page while programming +tools.bootburn.erase.params.verbose= +tools.bootburn.erase.params.quiet= +tools.bootburn.erase.pattern= + diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B112_ublox/pins_arduino.h b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B112_ublox/pins_arduino.h new file mode 100644 index 0000000..3ef4d4a --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B112_ublox/pins_arduino.h @@ -0,0 +1,17 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 +*/ + +// API compatibility +#include "variant.h" diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B112_ublox/variant.cpp b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B112_ublox/variant.cpp new file mode 100644 index 0000000..a68820c --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B112_ublox/variant.cpp @@ -0,0 +1,62 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ +// Thanks to great work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip). +// See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) + +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" +#include "nrf.h" + +const uint32_t g_ADigitalPinMap[] = { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31 + }; + diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B112_ublox/variant.h b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B112_ublox/variant.h new file mode 100644 index 0000000..42c7791 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B112_ublox/variant.h @@ -0,0 +1,173 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ + +#ifndef _VARIANT_NINA_B112_UBLOX_ +#define _VARIANT_NINA_B112_UBLOX_ + +#define NRF_CLOCK_LFCLKSRC {.source = NRF_CLOCK_LF_SRC_XTAL, \ + .rc_ctiv = 0, \ +.rc_temp_ctiv = 0, \ +.xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM} + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (32u) +#define NUM_DIGITAL_PINS (32u) +#define NUM_ANALOG_INPUTS (6u) +#define NUM_ANALOG_OUTPUTS (0u) + +// LEDs +#define PIN_LED LED1 +#define LED_BUILTIN PIN_LED + +//LEDs onboard +#define LED1 (8) // Red +#define LED2 (16) // Green/SW1 +#define LED3 (18) // Blue + +#define LED_STATE_ON 1 // State when LED is litted + +//Switch + +#define SW1 (16) +#define SW2 (30) + +// NFC +#define PIN_NFC_1 (9) // P0.9 +#define PIN_NFC_2 (10) // P0.10 + +/* + * Analog pins + */ +#define PIN_A0 (3) // P0.03 +#define PIN_A1 (2) // P0.02 +#define PIN_A2 (4) // P0.04 +#define PIN_A3 (30) // P0.30 +#define PIN_A4 (29) // P0.29 +#define PIN_A5 (28) // P0.28 + +static const uint8_t A0 = PIN_A0 ; +static const uint8_t A1 = PIN_A1 ; +static const uint8_t A2 = PIN_A2 ; +static const uint8_t A3 = PIN_A3 ; +static const uint8_t A4 = PIN_A4 ; +static const uint8_t A5 = PIN_A5 ; + +#define ADC_RESOLUTION 14 + +#define PIN_D0 (5) // P0.05 +#define PIN_D1 (6) // P0.06 +#define PIN_D2 (7) // P0.07 +#define PIN_D3 (31) // P0.31 +#define PIN_D4 (18) // P0.18 +#define PIN_D6 (9) // P0.09 +#define PIN_D7 (10) // P0.10 +#define PIN_D9 (8) // P0.8 +#define PIN_D10 (11) // P0.11 +#define PIN_D11 (13) // P0.13 +#define PIN_D12 (12) // P0.12 +#define PIN_D13 (14) // P0.14 +#define PIN_D14 (2) // P0.02 +#define PIN_D15 (3) // P0.03 + +static const uint8_t D0 = PIN_D0 ; +static const uint8_t D1 = PIN_D1 ; +static const uint8_t D2 = PIN_D2 ; +static const uint8_t D3 = PIN_D3 ; +static const uint8_t D4 = PIN_D4 ; +static const uint8_t D6 = PIN_D6 ; +static const uint8_t D7 = PIN_D7 ; +static const uint8_t D9 = PIN_D9 ; +static const uint8_t D10 = PIN_D10 ; +static const uint8_t D11 = PIN_D11 ; +static const uint8_t D12 = PIN_D12 ; +static const uint8_t D13 = PIN_D13 ; +static const uint8_t D14 = PIN_D14 ; +static const uint8_t D15 = PIN_D15 ; + +// Other pins +//static const uint8_t AREF = PIN_AREF; + +//#define PIN_AREF (24) +//#define PIN_VBAT PIN_A7 + +/* + * Serial interfaces + */ +//#define PIN_SERIAL_RX (8) //used for original Adafruit Bootloader +//#define PIN_SERIAL_TX (6) //used for original Adafruit Bootloader + +#define PIN_SERIAL_RX (5) // P0.05 +#define PIN_SERIAL_TX (6) // P0.06 +#define PIN_SERIAL_CTS (7) // P0.07 +#define PIN_SERIAL_RTS (31) // P0.31 +#define PIN_SERIAL_DTR (28) // P0.28 +#define PIN_SERIAL_DSR (29) // P0.29 + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (12) // P0.12 +#define PIN_SPI_MOSI (13) // P0.13 +#define PIN_SPI_SCK (14) // P0.14 + +static const uint8_t SS = 11 ; // P0.11 +static const uint8_t MOSI = PIN_SPI_MOSI ; +static const uint8_t MISO = PIN_SPI_MISO ; +static const uint8_t SCK = PIN_SPI_SCK ; + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (2) // P0.02 +#define PIN_WIRE_SCL (3) // P0.03 + +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; + + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + + +#endif //_VARIANT_NINA_B112_UBLOX_ diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B302_ublox/pins_arduino.h b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B302_ublox/pins_arduino.h new file mode 100644 index 0000000..3ef4d4a --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B302_ublox/pins_arduino.h @@ -0,0 +1,17 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 +*/ + +// API compatibility +#include "variant.h" diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B302_ublox/variant.cpp b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B302_ublox/variant.cpp new file mode 100644 index 0000000..b51ac2f --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B302_ublox/variant.cpp @@ -0,0 +1,109 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ +// Thanks to great work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip). +// See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) + +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" +#include "nrf.h" + +const uint32_t g_ADigitalPinMap[] = +{ + // D0 .. D13 + 29, // D0 is P0.29 (UART TX) + 45, // D1 is P1.13 (UART RX + 44, // D2 is P1.12 (NFC2) + 31, // D3 is P0.31 (LED1) + 13, // D4 is P0.13 (LED2) + 11, // D5 is P0.11 + 9, // D6 is P0.09 + 10, // D7 is P0.10 (Button) + 41, // D8 is P1.09 (NeoPixel) + 12, // D9 is P0.12 + 14, // D10 is P0.14 + 15, // D11 is P0.15 + 32, // D12 is P1.00 + 7, // D13 is P0.07 + + // D14 .. D21 (aka A0 .. A7) + 4, // D14 is P0.04 (A0) + 30, // D15 is P0.30 (A1) + 5, // D16 is P0.05 (A2) + 2, // D17 is P0.02 (A3) + 28, // D18 is P0.28 (A4) + 3, // D19 is P0.03 (A5) + 29, // D20 is P0.29 (A6, Battery) ???? + 31, // D21 is P0.31 (A7, ARef) ???? + + // D22 .. D23 (aka I2C pins) + 16, // D22 is P0.16 (SDA) + 24, // D23 is P0.24 (SCL) + + // D24 .. D26 (aka SPI pins) + 32, // D24 is P1.00 (SPI MISO) + 15, // D25 is P0.15 (SPI MOSI) + 7, // D26 is P0.07 (SPI SCK ) + + // QSPI pins (not exposed via any header / test point) + 19, // D27 is P0.19 (QSPI CLK) + 17, // D28 is P0.17 (QSPI CS) + 20, // D29 is P0.20 (QSPI Data 0) + 21, // D30 is P0.21 (QSPI Data 1) + 22, // D31 is P0.22 (QSPI Data 2) + 23, // D32 is P0.23 (QSPI Data 3) + + // The remaining NFC pin + 9, // D33 is P0.09 (NFC1, exposed only via test point on bottom of board) + + // Thus, there are 34 defined pins + + // The remaining pins are not usable: + // + // + // The following pins were never listed as they were considered unusable + // 0, // P0.00 is XL1 (attached to 32.768kHz crystal) + // 1, // P0.01 is XL2 (attached to 32.768kHz crystal) + // 18, // P0.18 is RESET (attached to switch) + // 32, // P1.00 is SWO (attached to debug header) + // + // The remaining pins are not connected (per schematic) + // 33, // P1.01 is not connected per schematic + // 35, // P1.03 is not connected per schematic + // 36, // P1.04 is not connected per schematic + // 37, // P1.05 is not connected per schematic + // 38, // P1.06 is not connected per schematic + // 39, // P1.07 is not connected per schematic + // 43, // P1.11 is not connected per schematic + // 44, // P1.12 is not connected per schematic + // 45, // P1.13 is not connected per schematic + // 46, // P1.14 is not connected per schematic +}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); +} + diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B302_ublox/variant.h b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B302_ublox/variant.h new file mode 100644 index 0000000..a5b7eb9 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.1/variants/NINA_B302_ublox/variant.h @@ -0,0 +1,159 @@ + /* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ + +// Thanks to great work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip). +// See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) + +#ifndef _VARIANT_NINA_B302_UBLOX_ +#define _VARIANT_NINA_B302_UBLOX_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus +// (XX) = TABLE INDEX +// Number of pins defined in PinDescription array +#define PINS_COUNT (34) +#define NUM_DIGITAL_PINS (34) +#define NUM_ANALOG_INPUTS (6) // A6 is used for battery, A7 is analog reference +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (3) +#define PIN_LED2 (4) +#define PIN_NEOPIXEL (8) + +#define LED_BUILTIN PIN_LED1 +#define LED_CONN PIN_LED2 + +#define LED_RED PIN_LED1 +#define LED_BLUE PIN_LED2 + +#define LED_STATE_ON 1 // State when LED is litted + +/* + * Buttons + */ +#define PIN_BUTTON1 (7) + +/* + * Analog pins + */ +#define PIN_A0 (14) +#define PIN_A1 (15) +#define PIN_A2 (16) +#define PIN_A3 (17) +#define PIN_A4 (18) +#define PIN_A5 (19) +#define PIN_A6 (20) +#define PIN_A7 (21) + +#define D0 (0) +#define D1 (1) +#define D2 (2) +#define D3 (3) +#define D4 (4) +#define D5 (5) +#define D6 (6) +#define D7 (7) +#define D8 (8) +#define D9 (9) +#define D10 (10) +#define D11 (11) +#define D12 (12) +#define D13 (13) + +static const uint8_t A0 = PIN_A0 ; +static const uint8_t A1 = PIN_A1 ; +static const uint8_t A2 = PIN_A2 ; +static const uint8_t A3 = PIN_A3 ; +static const uint8_t A4 = PIN_A4 ; +static const uint8_t A5 = PIN_A5 ; +static const uint8_t A6 = PIN_A6 ; +static const uint8_t A7 = PIN_A7 ; +#define ADC_RESOLUTION 14 + +// Other pins +#define PIN_AREF PIN_A7 +#define PIN_VBAT PIN_A6 +#define PIN_NFC1 (33) +#define PIN_NFC2 (2) + +static const uint8_t AREF = PIN_AREF; + +/* + * Serial interfaces + */ +#define PIN_SERIAL1_RX (1) +#define PIN_SERIAL1_TX (0) + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (24) //24 original +#define PIN_SPI_MOSI (25) //25 original +#define PIN_SPI_SCK (26) //26 original + +static const uint8_t SS = (13); +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (22) +#define PIN_WIRE_SCL (23) + +// QSPI Pins +#define PIN_QSPI_SCK 27 +#define PIN_QSPI_CS 28 +#define PIN_QSPI_IO0 29 +#define PIN_QSPI_IO1 30 +#define PIN_QSPI_IO2 31 +#define PIN_QSPI_IO3 32 + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES GD25Q16C +#define EXTERNAL_FLASH_USE_QSPI + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif //_VARIANT_NINA_B302_UBLOX_ diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.5/boards.txt b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/boards.txt new file mode 100644 index 0000000..5aee8ca --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/boards.txt @@ -0,0 +1,649 @@ +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# Copyright (c) 2016 Sandeep Mistry All right reserved. +# Copyright (c) 2017 Adafruit Industries. 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 + +menu.softdevice=Bootloader +menu.debug=Debug + +# ---------------------------------- +# Bluefruit Feather nRF52832 +# ---------------------------------- +feather52832.name=Adafruit Feather nRF52832 +feather52832.bootloader.tool=bootburn + +# Upload +feather52832.upload.tool=nrfutil +feather52832.upload.protocol=nrfutil +feather52832.upload.use_1200bps_touch=false +feather52832.upload.wait_for_upload_port=false +feather52832.upload.native_usb=false +feather52832.upload.maximum_size=290816 +feather52832.upload.maximum_data_size=52224 + +# Build +feather52832.build.mcu=cortex-m4 +feather52832.build.f_cpu=64000000 +feather52832.build.board=NRF52832_FEATHER +feather52832.build.core=nRF5 +feather52832.build.variant=feather_nrf52832 +feather52832.build.usb_manufacturer="Adafruit LLC" +feather52832.build.usb_product="Feather nRF52832" +feather52832.build.extra_flags=-DNRF52832_XXAA -DNRF52832_FEATHER -DNRF52 +feather52832.build.ldscript=nrf52832_s132_v6.ld + +# SofDevice Menu +feather52832.menu.softdevice.s132v6=0.3.2 SoftDevice s132 6.1.1 +feather52832.menu.softdevice.s132v6.build.sd_name=s132 +feather52832.menu.softdevice.s132v6.build.sd_version=6.1.1 +feather52832.menu.softdevice.s132v6.build.sd_fwid=0x00B7 + +# Debug Menu +feather52832.menu.debug.l0=Level 0 (Release) +feather52832.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +feather52832.menu.debug.l1=Level 1 (Error Message) +feather52832.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +feather52832.menu.debug.l2=Level 2 (Full Debug) +feather52832.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +feather52832.menu.debug.l3=Level 3 (Segger SystemView) +feather52832.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +feather52832.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Bluefruit Feather nRF52840 Express +# ---------------------------------- +feather52840.name=Adafruit Feather nRF52840 Express + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +feather52840.vid.0=0x239A +feather52840.pid.0=0x8029 +feather52840.vid.1=0x239A +feather52840.pid.1=0x0029 +feather52840.vid.2=0x239A +feather52840.pid.2=0x002A +feather52840.vid.3=0x239A +feather52840.pid.3=0x802A + +# Upload +feather52840.bootloader.tool=bootburn +feather52840.upload.tool=nrfutil +feather52840.upload.protocol=nrfutil +feather52840.upload.use_1200bps_touch=true +feather52840.upload.wait_for_upload_port=true +feather52840.upload.maximum_size=815104 +feather52840.upload.maximum_data_size=237568 + +# Build +feather52840.build.mcu=cortex-m4 +feather52840.build.f_cpu=64000000 +feather52840.build.board=NRF52840_FEATHER +feather52840.build.core=nRF5 +feather52840.build.variant=feather_nrf52840_express +feather52840.build.usb_manufacturer="Adafruit LLC" +feather52840.build.usb_product="Feather nRF52840 Express" +feather52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_FEATHER {build.flags.usb} +feather52840.build.ldscript=nrf52840_s140_v6.ld +feather52840.build.vid=0x239A +feather52840.build.pid=0x8029 + +# SofDevice Menu +feather52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +feather52840.menu.softdevice.s140v6.build.sd_name=s140 +feather52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +feather52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +feather52840.menu.debug.l0=Level 0 (Release) +feather52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +feather52840.menu.debug.l1=Level 1 (Error Message) +feather52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +feather52840.menu.debug.l2=Level 2 (Full Debug) +feather52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +feather52840.menu.debug.l3=Level 3 (Segger SystemView) +feather52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +feather52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + +# ---------------------------------- +# Feather Bluefruit sense +# ---------------------------------- +feather52840sense.name=Adafruit Feather Bluefruit Sense + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +feather52840sense.vid.0=0x239A +feather52840sense.pid.0=0x8087 +feather52840sense.vid.1=0x239A +feather52840sense.pid.1=0x0087 +feather52840sense.vid.2=0x239A +feather52840sense.pid.2=0x0088 +feather52840sense.vid.3=0x239A +feather52840sense.pid.3=0x8088 + +# Upload +feather52840sense.bootloader.tool=bootburn +feather52840sense.upload.tool=nrfutil +feather52840sense.upload.protocol=nrfutil +feather52840sense.upload.use_1200bps_touch=true +feather52840sense.upload.wait_for_upload_port=true +feather52840sense.upload.maximum_size=815104 +feather52840sense.upload.maximum_data_size=237568 + +# Build +feather52840sense.build.mcu=cortex-m4 +feather52840sense.build.f_cpu=64000000 +feather52840sense.build.board=NRF52840_FEATHER_SENSE +feather52840sense.build.core=nRF5 +feather52840sense.build.variant=feather_nrf52840_sense +feather52840sense.build.usb_manufacturer="Adafruit LLC" +feather52840sense.build.usb_product="Feather nRF52840 Sense" +feather52840sense.build.extra_flags=-DNRF52840_XXAA -DNRF52840_FEATHER_SENSE {build.flags.usb} +feather52840sense.build.ldscript=nrf52840_s140_v6.ld +feather52840sense.build.vid=0x239A +feather52840sense.build.pid=0x8087 + +# SofDevice Menu +feather52840sense.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +feather52840sense.menu.softdevice.s140v6.build.sd_name=s140 +feather52840sense.menu.softdevice.s140v6.build.sd_version=6.1.1 +feather52840sense.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +feather52840sense.menu.debug.l0=Level 0 (Release) +feather52840sense.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +feather52840sense.menu.debug.l1=Level 1 (Error Message) +feather52840sense.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +feather52840sense.menu.debug.l2=Level 2 (Full Debug) +feather52840sense.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +feather52840sense.menu.debug.l3=Level 3 (Segger SystemView) +feather52840sense.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +feather52840sense.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + +# --------------------------------------------- +# Bluefruit ItsyBitsy nRF52840 Express +# --------------------------------------------- +itsybitsy52840.name=Adafruit ItsyBitsy nRF52840 Express + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +itsybitsy52840.vid.0=0x239A +itsybitsy52840.pid.0=0x8051 +itsybitsy52840.vid.1=0x239A +itsybitsy52840.pid.1=0x0051 +itsybitsy52840.vid.2=0x239A +itsybitsy52840.pid.2=0x0052 +itsybitsy52840.vid.3=0x239A +itsybitsy52840.pid.3=0x8052 + +# Upload +itsybitsy52840.bootloader.tool=bootburn +itsybitsy52840.upload.tool=nrfutil +itsybitsy52840.upload.protocol=nrfutil +itsybitsy52840.upload.use_1200bps_touch=true +itsybitsy52840.upload.wait_for_upload_port=true +itsybitsy52840.upload.maximum_size=815104 +itsybitsy52840.upload.maximum_data_size=237568 + +# Build +itsybitsy52840.build.mcu=cortex-m4 +itsybitsy52840.build.f_cpu=64000000 +itsybitsy52840.build.board=NRF52840_ITSYBITSY +itsybitsy52840.build.core=nRF5 +itsybitsy52840.build.variant=itsybitsy_nrf52840_express +itsybitsy52840.build.usb_manufacturer="Adafruit LLC" +itsybitsy52840.build.usb_product="ItsyBitsy nRF52840 Express" +itsybitsy52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_ITSYBITSY -DARDUINO_NRF52_ITSYBITSY {build.flags.usb} +itsybitsy52840.build.ldscript=nrf52840_s140_v6.ld +itsybitsy52840.build.vid=0x239A +itsybitsy52840.build.pid=0x8051 + +# SofDevice Menu +itsybitsy52840.menu.softdevice.s140v6=0.2.11 SoftDevice s140 6.1.1 +itsybitsy52840.menu.softdevice.s140v6.build.sd_name=s140 +itsybitsy52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +itsybitsy52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +itsybitsy52840.menu.debug.l0=Level 0 (Release) +itsybitsy52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +itsybitsy52840.menu.debug.l1=Level 1 (Error Message) +itsybitsy52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +itsybitsy52840.menu.debug.l2=Level 2 (Full Debug) +itsybitsy52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +itsybitsy52840.menu.debug.l3=Level 3 (Segger SystemView) +itsybitsy52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +itsybitsy52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# --------------------------------------------- +# Bluefruit Circuit Playground nRF52840 Express +# --------------------------------------------- +cplaynrf52840.name=Adafruit Circuit Playground Bluefruit + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +cplaynrf52840.vid.0=0x239A +cplaynrf52840.pid.0=0x8045 +cplaynrf52840.vid.1=0x239A +cplaynrf52840.pid.1=0x0045 +cplaynrf52840.vid.2=0x239A +cplaynrf52840.pid.2=0x0046 +cplaynrf52840.vid.3=0x239A +cplaynrf52840.pid.3=0x8046 + +# Upload +cplaynrf52840.bootloader.tool=bootburn +cplaynrf52840.upload.tool=nrfutil +cplaynrf52840.upload.protocol=nrfutil +cplaynrf52840.upload.use_1200bps_touch=true +cplaynrf52840.upload.wait_for_upload_port=true +cplaynrf52840.upload.maximum_size=815104 +cplaynrf52840.upload.maximum_data_size=237568 + +# Build +cplaynrf52840.build.mcu=cortex-m4 +cplaynrf52840.build.f_cpu=64000000 +cplaynrf52840.build.board=NRF52840_CIRCUITPLAY +cplaynrf52840.build.core=nRF5 +cplaynrf52840.build.variant=circuitplayground_nrf52840 +cplaynrf52840.build.usb_manufacturer="Adafruit LLC" +cplaynrf52840.build.usb_product="Circuit Playground Bluefruit" +cplaynrf52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_CIRCUITPLAY {build.flags.usb} +cplaynrf52840.build.ldscript=nrf52840_s140_v6.ld +cplaynrf52840.build.vid=0x239A +cplaynrf52840.build.pid=0x8045 + +# SofDevice Menu +cplaynrf52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +cplaynrf52840.menu.softdevice.s140v6.build.sd_name=s140 +cplaynrf52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +cplaynrf52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +cplaynrf52840.menu.debug.l0=Level 0 (Release) +cplaynrf52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +cplaynrf52840.menu.debug.l1=Level 1 (Error Message) +cplaynrf52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +cplaynrf52840.menu.debug.l2=Level 2 (Full Debug) +cplaynrf52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +cplaynrf52840.menu.debug.l3=Level 3 (Segger SystemView) +cplaynrf52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +cplaynrf52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + +# --------------------------------------------- +# Clue nRF52840 +# --------------------------------------------- +cluenrf52840.name=Adafruit CLUE + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +cluenrf52840.vid.0=0x239A +cluenrf52840.pid.0=0x8072 +cluenrf52840.vid.1=0x239A +cluenrf52840.pid.1=0x0072 +cluenrf52840.vid.2=0x239A +cluenrf52840.pid.2=0x0071 +cluenrf52840.vid.3=0x239A +cluenrf52840.pid.3=0x8071 + +# Upload +cluenrf52840.bootloader.tool=bootburn +cluenrf52840.upload.tool=nrfutil +cluenrf52840.upload.protocol=nrfutil +cluenrf52840.upload.use_1200bps_touch=true +cluenrf52840.upload.wait_for_upload_port=true +cluenrf52840.upload.maximum_size=815104 +cluenrf52840.upload.maximum_data_size=237568 + +# Build +cluenrf52840.build.mcu=cortex-m4 +cluenrf52840.build.f_cpu=64000000 +cluenrf52840.build.board=NRF52840_CLUE +cluenrf52840.build.core=nRF5 +cluenrf52840.build.variant=clue_nrf52840 +cluenrf52840.build.usb_manufacturer="Adafruit LLC" +cluenrf52840.build.usb_product="CLUE" +cluenrf52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_CLUE {build.flags.usb} +cluenrf52840.build.ldscript=nrf52840_s140_v6.ld +cluenrf52840.build.vid=0x239A +cluenrf52840.build.pid=0x8071 + +# SofDevice Menu +cluenrf52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +cluenrf52840.menu.softdevice.s140v6.build.sd_name=s140 +cluenrf52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +cluenrf52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +cluenrf52840.menu.debug.l0=Level 0 (Release) +cluenrf52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +cluenrf52840.menu.debug.l1=Level 1 (Error Message) +cluenrf52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +cluenrf52840.menu.debug.l2=Level 2 (Full Debug) +cluenrf52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +cluenrf52840.menu.debug.l3=Level 3 (Segger SystemView) +cluenrf52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +cluenrf52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Bluefruit Metro nRF52840 Express +# ---------------------------------- +metro52840.name=Adafruit Bluefruit Metro nRF52840 Express + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +metro52840.vid.0=0x239A +metro52840.pid.0=0x803F +metro52840.vid.1=0x239A +metro52840.pid.1=0x003F +metro52840.vid.2=0x239A +metro52840.pid.2=0x0040 +metro52840.vid.3=0x239A +metro52840.pid.3=0x8040 + +# Upload +metro52840.bootloader.tool=bootburn +metro52840.upload.tool=nrfutil +metro52840.upload.protocol=nrfutil +metro52840.upload.use_1200bps_touch=true +metro52840.upload.wait_for_upload_port=true +metro52840.upload.maximum_size=815104 +metro52840.upload.maximum_data_size=237568 + +# Build +metro52840.build.mcu=cortex-m4 +metro52840.build.f_cpu=64000000 +metro52840.build.board=NRF52840_METRO +metro52840.build.core=nRF5 +metro52840.build.variant=metro_nrf52840_express +metro52840.build.usb_manufacturer="Adafruit LLC" +metro52840.build.usb_product="Metro nRF52840 Express" +metro52840.build.extra_flags=-DNRF52840_XXAA -DNRF52840_METRO {build.flags.usb} +metro52840.build.ldscript=nrf52840_s140_v6.ld +metro52840.build.vid=0x239A +metro52840.build.pid=0x803F + +# SofDevice Menu +metro52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +metro52840.menu.softdevice.s140v6.build.sd_name=s140 +metro52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +metro52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +metro52840.menu.debug.l0=Level 0 (Release) +metro52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +metro52840.menu.debug.l1=Level 1 (Error Message) +metro52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +metro52840.menu.debug.l2=Level 2 (Full Debug) +metro52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +metro52840.menu.debug.l3=Level 3 (Segger SystemView) +metro52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +metro52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + + + +# ------------------------------------------------------- +# +# Boards that aren't made by Adafruit +# +# ------------------------------------------------------- + + +# ---------------------------------- +# Nordic nRF52840DK (PCA10056) +# ---------------------------------- +pca10056.name=Nordic nRF52840DK (PCA10056) +pca10056.bootloader.tool=bootburn + +# Upload +pca10056.upload.tool=nrfutil +pca10056.upload.protocol=nrfutil +pca10056.upload.use_1200bps_touch=true +pca10056.upload.wait_for_upload_port=true +pca10056.upload.maximum_size=815104 +pca10056.upload.maximum_data_size=237568 + +# Build +pca10056.build.mcu=cortex-m4 +pca10056.build.f_cpu=64000000 +pca10056.build.board=NRF52840_PCA10056 +pca10056.build.core=nRF5 +pca10056.build.variant=pca10056 +pca10056.build.usb_manufacturer="Nordic" +pca10056.build.usb_product="nRF52840 DK" +pca10056.build.extra_flags=-DNRF52840_XXAA -DNRF52840_PCA10056 {build.flags.usb} +pca10056.build.ldscript=nrf52840_s140_v6.ld +pca10056.build.vid=0x239A +pca10056.build.pid=0x8029 + +# SofDevice Menu +pca10056.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +pca10056.menu.softdevice.s140v6.build.sd_name=s140 +pca10056.menu.softdevice.s140v6.build.sd_version=6.1.1 +pca10056.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +pca10056.menu.debug.l0=Level 0 (Release) +pca10056.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +pca10056.menu.debug.l1=Level 1 (Error Message) +pca10056.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +pca10056.menu.debug.l2=Level 2 (Full Debug) +pca10056.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +pca10056.menu.debug.l3=Level 3 (Segger SystemView) +pca10056.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +pca10056.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Particle Xenon +# ---------------------------------- +particle_xenon.name=Particle Xenon + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +particle_xenon.vid.0=0x239A +particle_xenon.pid.0=0x8029 +particle_xenon.vid.1=0x239A +particle_xenon.pid.1=0x0029 +particle_xenon.vid.2=0x239A +particle_xenon.pid.2=0x002A +particle_xenon.vid.3=0x239A +particle_xenon.pid.3=0x802A + +# Upload +particle_xenon.bootloader.tool=bootburn +particle_xenon.upload.tool=nrfutil +particle_xenon.upload.protocol=nrfutil +particle_xenon.upload.use_1200bps_touch=true +particle_xenon.upload.wait_for_upload_port=true +particle_xenon.upload.maximum_size=815104 +particle_xenon.upload.maximum_data_size=237568 + +# Build +particle_xenon.build.mcu=cortex-m4 +particle_xenon.build.f_cpu=64000000 +particle_xenon.build.board=PARTICLE_XENON +particle_xenon.build.core=nRF5 +particle_xenon.build.variant=particle_xenon +particle_xenon.build.usb_manufacturer="Particle Industries" +particle_xenon.build.usb_product="Particle Xenon" +particle_xenon.build.extra_flags=-DNRF52840_XXAA -DPARTICLE_XENON {build.flags.usb} +particle_xenon.build.ldscript=nrf52840_s140_v6.ld +particle_xenon.build.vid=0x239A +particle_xenon.build.pid=0x8029 + +# SofDevice Menu +particle_xenon.menu.softdevice.s140v6=0.2.11 SoftDevice s140 6.1.1 +particle_xenon.menu.softdevice.s140v6.build.sd_name=s140 +particle_xenon.menu.softdevice.s140v6.build.sd_version=6.1.1 +particle_xenon.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +particle_xenon.menu.debug.l0=Level 0 (Release) +particle_xenon.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +particle_xenon.menu.debug.l1=Level 1 (Error Message) +particle_xenon.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +particle_xenon.menu.debug.l2=Level 2 (Full Debug) +particle_xenon.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +particle_xenon.menu.debug.l3=Level 3 (Segger SystemView) +particle_xenon.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +particle_xenon.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Raytac MDBT50Q - RX +# ---------------------------------- +mdbt50qrx.name=Raytac MDBT50Q-RX Dongle + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +mdbt50qrx.vid.0=0x239A +mdbt50qrx.pid.0=0x8029 +mdbt50qrx.vid.1=0x239A +mdbt50qrx.pid.1=0x0029 +mdbt50qrx.vid.2=0x239A +mdbt50qrx.pid.2=0x002A +mdbt50qrx.vid.3=0x239A +mdbt50qrx.pid.3=0x802A + +# Upload +mdbt50qrx.bootloader.tool=bootburn +mdbt50qrx.upload.tool=nrfutil +mdbt50qrx.upload.protocol=nrfutil +mdbt50qrx.upload.use_1200bps_touch=true +mdbt50qrx.upload.wait_for_upload_port=true +mdbt50qrx.upload.maximum_size=815104 +mdbt50qrx.upload.maximum_data_size=237568 + +# Build +mdbt50qrx.build.mcu=cortex-m4 +mdbt50qrx.build.f_cpu=64000000 +mdbt50qrx.build.board=MDBT50Q_RX +mdbt50qrx.build.core=nRF5 +mdbt50qrx.build.variant=raytac_mdbt50q_rx +mdbt50qrx.build.usb_manufacturer="Raytac Corporation" +mdbt50qrx.build.usb_product="Raytac MDBT50Q - RX" +mdbt50qrx.build.extra_flags=-DNRF52840_XXAA -DMDBT50Q_RX {build.flags.usb} +mdbt50qrx.build.ldscript=nrf52840_s140_v6.ld +mdbt50qrx.build.vid=0x239A +mdbt50qrx.build.pid=0x8029 + +# SofDevice Menu +mdbt50qrx.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +mdbt50qrx.menu.softdevice.s140v6.build.sd_name=s140 +mdbt50qrx.menu.softdevice.s140v6.build.sd_version=6.1.1 +mdbt50qrx.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +mdbt50qrx.menu.debug.l0=Level 0 (Release) +mdbt50qrx.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +mdbt50qrx.menu.debug.l1=Level 1 (Error Message) +mdbt50qrx.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +mdbt50qrx.menu.debug.l2=Level 2 (Full Debug) +mdbt50qrx.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +mdbt50qrx.menu.debug.l3=Level 3 (Segger SystemView) +mdbt50qrx.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +mdbt50qrx.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# NINA B302 +# ---------------------------------- +ninab302.name=NINA B302 ublox + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +ninab302.vid.0=0x239A +ninab302.pid.0=0x8029 +ninab302.vid.1=0x239A +ninab302.pid.1=0x0029 +ninab302.vid.2=0x7239A +ninab302.pid.2=0x002A +ninab302.vid.3=0x239A +ninab302.pid.3=0x802A + +# Upload +ninab302.bootloader.tool=bootburn +ninab302.upload.tool=nrfutil +ninab302.upload.protocol=nrfutil +ninab302.upload.use_1200bps_touch=true +ninab302.upload.wait_for_upload_port=true +ninab302.upload.maximum_size=815104 +ninab302.upload.maximum_data_size=237568 + +# Build +ninab302.build.mcu=cortex-m4 +ninab302.build.f_cpu=64000000 +ninab302.build.board=NINA_B302_ublox +ninab302.build.core=nRF5 +ninab302.build.variant=NINA_B302_ublox +ninab302.build.usb_manufacturer="Nordic" +ninab302.build.usb_product="NINA B302 ublox" +ninab302.build.extra_flags=-DNRF52840_XXAA -DNINA_B302_ublox {build.flags.usb} +ninab302.build.ldscript=nrf52840_s140_v6.ld +ninab302.build.vid=0x239A +ninab302.build.pid=0x8029 + +# SofDevice Menu +ninab302.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +ninab302.menu.softdevice.s140v6.build.sd_name=s140 +ninab302.menu.softdevice.s140v6.build.sd_version=6.1.1 +ninab302.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +ninab302.menu.debug.l0=Level 0 (Release) +ninab302.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +ninab302.menu.debug.l1=Level 1 (Error Message) +ninab302.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +ninab302.menu.debug.l2=Level 2 (Full Debug) +ninab302.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +ninab302.menu.debug.l3=Level 3 (Segger SystemView) +ninab302.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +ninab302.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# NINA B112 +# ---------------------------------- +ninab112.name=NINA B112 ublox +ninab112.bootloader.tool=bootburn + +# Upload +ninab112.upload.tool=nrfutil +ninab112.upload.protocol=nrfutil +ninab112.upload.use_1200bps_touch=false +ninab112.upload.wait_for_upload_port=false +ninab112.upload.native_usb=false +ninab112.upload.maximum_size=290816 +ninab112.upload.maximum_data_size=52224 + +# Build +ninab112.build.mcu=cortex-m4 +ninab112.build.f_cpu=64000000 +ninab112.build.board=NINA_B112_ublox +ninab112.build.core=nRF5 +ninab112.build.variant=NINA_B112_ublox +feather52840.build.usb_manufacturer="Adafruit LLC" +feather52840.build.usb_product="Feather nRF52832" +ninab112.build.extra_flags=-DNRF52832_XXAA -DNINA_B112_ublox -DNRF52 +ninab112.build.ldscript=nrf52832_s132_v6.ld + +# SofDevice Menu +ninab112.menu.softdevice.s132v6=0.3.2 SoftDevice s132 6.1.1 +ninab112.menu.softdevice.s132v6.build.sd_name=s132 +ninab112.menu.softdevice.s132v6.build.sd_version=6.1.1 +ninab112.menu.softdevice.s132v6.build.sd_fwid=0x00B7 + +# Debug Menu +ninab112.menu.debug.l0=Level 0 (Release) +ninab112.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +ninab112.menu.debug.l1=Level 1 (Error Message) +ninab112.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +ninab112.menu.debug.l2=Level 2 (Full Debug) +ninab112.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +ninab112.menu.debug.l3=Level 3 (Segger SystemView) +ninab112.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +ninab112.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.5/cores/nRF5/Udp.h b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/cores/nRF5/Udp.h new file mode 100644 index 0000000..016042a --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/cores/nRF5/Udp.h @@ -0,0 +1,92 @@ +/* + * Udp.cpp: Library to send/receive UDP packets. + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef udp_h +#define udp_h + +#include +#include + +class UDP : public Stream { + +public: + virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + + // KH, add virtual function to support Multicast, necessary for many services (MDNS, etc.) + virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure + + virtual void stop() =0; // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port) =0; + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port) =0; + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket() =0; + // Write a single byte into the packet + virtual size_t write(uint8_t) =0; + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size) =0; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket() =0; + // Number of bytes remaining in the current packet + virtual int available() =0; + // Read a single byte from the current packet + virtual int read() =0; + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len) =0; + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) =0; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek() =0; + virtual void flush() =0; // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() =0; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() =0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.5/platform.txt b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/platform.txt new file mode 100644 index 0000000..6c7ed43 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/platform.txt @@ -0,0 +1,164 @@ +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# Copyright (c) 2016 Sandeep Mistry All right reserved. +# Copyright (c) 2017 Adafruit Industries. All rights reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +name=Adafruit nRF52 Boards +version=0.20.5 + +# Compile variables +# ----------------- + +compiler.warning_flags=-w +compiler.warning_flags.none=-w +compiler.warning_flags.default= +compiler.warning_flags.more=-Wall +compiler.warning_flags.all=-Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wno-pointer-arith + +compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ +compiler.c.cmd=arm-none-eabi-gcc +compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD +# KH, Error here to use gcc, mjust use g++ +#compiler.c.elf.cmd=arm-none-eabi-gcc +compiler.c.elf.cmd=arm-none-eabi-g++ +compiler.c.elf.flags=-Ofast -Wl,--gc-sections -save-temps +compiler.S.cmd=arm-none-eabi-gcc +compiler.S.flags=-c -g -x assembler-with-cpp +compiler.cpp.cmd=arm-none-eabi-g++ +compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD +compiler.ar.cmd=arm-none-eabi-ar +compiler.ar.flags=rcs +compiler.objcopy.cmd=arm-none-eabi-objcopy +compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 +compiler.elf2bin.flags=-O binary +compiler.elf2bin.cmd=arm-none-eabi-objcopy +compiler.elf2hex.flags=-O ihex +compiler.elf2hex.cmd=arm-none-eabi-objcopy +compiler.ldflags=-mcpu={build.mcu} -mthumb {build.float_flags} -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align --specs=nano.specs --specs=nosys.specs +compiler.size.cmd=arm-none-eabi-size + +# this can be overriden in boards.txt +build.float_flags=-mfloat-abi=hard -mfpu=fpv4-sp-d16 -u _printf_float +build.debug_flags=-DCFG_DEBUG=0 +build.logger_flags=-DCFG_LOGGER=1 +build.sysview_flags=-DCFG_SYSVIEW=0 + +# common compiler for nrf +rtos.path={build.core.path}/freertos +nordic.path={build.core.path}/nordic + +# build.logger_flags and build.sysview_flags and intentionally empty, +# to allow modification via a user's own boards.local.txt or platform.local.txt files. +build.flags.nrf= -DSOFTDEVICE_PRESENT -DARDUINO_NRF52_ADAFRUIT -DNRF52_SERIES -DLFS_NAME_MAX=64 -Ofast {build.debug_flags} {build.logger_flags} {build.sysview_flags} "-I{build.core.path}/cmsis/Core/Include" "-I{nordic.path}" "-I{nordic.path}/nrfx" "-I{nordic.path}/nrfx/hal" "-I{nordic.path}/nrfx/mdk" "-I{nordic.path}/nrfx/soc" "-I{nordic.path}/nrfx/drivers/include" "-I{nordic.path}/nrfx/drivers/src" "-I{nordic.path}/softdevice/{build.sd_name}_nrf52_{build.sd_version}_API/include" "-I{rtos.path}/Source/include" "-I{rtos.path}/config" "-I{rtos.path}/portable/GCC/nrf52" "-I{rtos.path}/portable/CMSIS/nrf52" "-I{build.core.path}/sysview/SEGGER" "-I{build.core.path}/sysview/Config" "-I{build.core.path}/TinyUSB" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore/tinyusb/src" + +# usb flags +build.flags.usb= -DUSBCON -DUSE_TINYUSB -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' + +# These can be overridden in platform.local.txt +compiler.c.extra_flags= +compiler.c.elf.extra_flags= +compiler.cpp.extra_flags= +compiler.S.extra_flags= +compiler.ar.extra_flags= +compiler.elf2bin.extra_flags= +compiler.elf2hex.extra_flags= + + +# Compile patterns +# ---------------- + +## Compile c files +## KH Add -DBOARD_NAME="{build.board}" +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.c.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +##recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.c.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +## Compile c++ files +## KH Add -DBOARD_NAME="{build.board}" +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.cpp.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +##recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.cpp.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +## Compile S files +## KH Add -DBOARD_NAME="{build.board}" +recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +##recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +## Create archives +recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" + +## Combine gc-sections, archives, and objects +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-L{build.core.path}/linker" "-T{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} -Wl,--start-group -lm "{build.path}/{archive_file}" -Wl,--end-group + +## Create output (bin file) +#recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2bin.cmd}" {compiler.elf2bin.flags} {compiler.elf2bin.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" + +## Create output (hex file) +recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" + +## Create dfu package zip file +recipe.objcopy.zip.pattern="{tools.nrfutil.cmd}" dfu genpkg --dev-type 0x0052 --sd-req {build.sd_fwid} --application "{build.path}/{build.project_name}.hex" "{build.path}/{build.project_name}.zip" + +## Create uf2 file +#recipe.objcopy.uf2.pattern=python "{runtime.platform.path}/tools/uf2conv/uf2conv.py" -f 0xADA52840 -c -o "{build.path}/{build.project_name}.uf2" "{build.path}/{build.project_name}.hex" + +## Save bin +recipe.output.tmp_file_bin={build.project_name}.bin +recipe.output.save_file_bin={build.project_name}.save.bin + +## Save hex +recipe.output.tmp_file_hex={build.project_name}.hex +recipe.output.save_file_hexu={build.project_name}.save.hex + +## Compute size +recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" +recipe.size.regex=^(?:\.text|\.data|)\s+([0-9]+).* +recipe.size.regex.data=^(?:\.data|\.bss)\s+([0-9]+).* + +## Export Compiled Binary +recipe.output.tmp_file={build.project_name}.hex +recipe.output.save_file={build.project_name}.{build.variant}.hex + +#*************************************************** +# adafruit-nrfutil for uploading +# https://github.com/adafruit/Adafruit_nRF52_nrfutil +# pre-built binaries are provided for macos and windows +#*************************************************** +tools.nrfutil.cmd=adafruit-nrfutil +tools.nrfutil.cmd.windows={runtime.platform.path}/tools/adafruit-nrfutil/win32/adafruit-nrfutil.exe +tools.nrfutil.cmd.macosx={runtime.platform.path}/tools/adafruit-nrfutil/macos/adafruit-nrfutil + +tools.nrfutil.upload.params.verbose=--verbose +tools.nrfutil.upload.params.quiet= +tools.nrfutil.upload.pattern="{cmd}" {upload.verbose} dfu serial -pkg "{build.path}/{build.project_name}.zip" -p {serial.port} -b 115200 --singlebank + +#*************************************************** +# Burning bootloader with either jlink or nrfutil +#*************************************************** + +# Bootloader version +tools.bootburn.bootloader.file={runtime.platform.path}/bootloader/{build.variant}/{build.variant}_bootloader-0.3.2_{build.sd_name}_{build.sd_version} + +tools.bootburn.bootloader.params.verbose= +tools.bootburn.bootloader.params.quiet= +tools.bootburn.bootloader.pattern={program.burn_pattern} + +# erase flash page while programming +tools.bootburn.erase.params.verbose= +tools.bootburn.erase.params.quiet= +tools.bootburn.erase.pattern= + diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B112_ublox/pins_arduino.h b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B112_ublox/pins_arduino.h new file mode 100644 index 0000000..3ef4d4a --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B112_ublox/pins_arduino.h @@ -0,0 +1,17 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 +*/ + +// API compatibility +#include "variant.h" diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B112_ublox/variant.cpp b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B112_ublox/variant.cpp new file mode 100644 index 0000000..a68820c --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B112_ublox/variant.cpp @@ -0,0 +1,62 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ +// Thanks to great work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip). +// See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) + +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" +#include "nrf.h" + +const uint32_t g_ADigitalPinMap[] = { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31 + }; + diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B112_ublox/variant.h b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B112_ublox/variant.h new file mode 100644 index 0000000..42c7791 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B112_ublox/variant.h @@ -0,0 +1,173 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ + +#ifndef _VARIANT_NINA_B112_UBLOX_ +#define _VARIANT_NINA_B112_UBLOX_ + +#define NRF_CLOCK_LFCLKSRC {.source = NRF_CLOCK_LF_SRC_XTAL, \ + .rc_ctiv = 0, \ +.rc_temp_ctiv = 0, \ +.xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM} + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (32u) +#define NUM_DIGITAL_PINS (32u) +#define NUM_ANALOG_INPUTS (6u) +#define NUM_ANALOG_OUTPUTS (0u) + +// LEDs +#define PIN_LED LED1 +#define LED_BUILTIN PIN_LED + +//LEDs onboard +#define LED1 (8) // Red +#define LED2 (16) // Green/SW1 +#define LED3 (18) // Blue + +#define LED_STATE_ON 1 // State when LED is litted + +//Switch + +#define SW1 (16) +#define SW2 (30) + +// NFC +#define PIN_NFC_1 (9) // P0.9 +#define PIN_NFC_2 (10) // P0.10 + +/* + * Analog pins + */ +#define PIN_A0 (3) // P0.03 +#define PIN_A1 (2) // P0.02 +#define PIN_A2 (4) // P0.04 +#define PIN_A3 (30) // P0.30 +#define PIN_A4 (29) // P0.29 +#define PIN_A5 (28) // P0.28 + +static const uint8_t A0 = PIN_A0 ; +static const uint8_t A1 = PIN_A1 ; +static const uint8_t A2 = PIN_A2 ; +static const uint8_t A3 = PIN_A3 ; +static const uint8_t A4 = PIN_A4 ; +static const uint8_t A5 = PIN_A5 ; + +#define ADC_RESOLUTION 14 + +#define PIN_D0 (5) // P0.05 +#define PIN_D1 (6) // P0.06 +#define PIN_D2 (7) // P0.07 +#define PIN_D3 (31) // P0.31 +#define PIN_D4 (18) // P0.18 +#define PIN_D6 (9) // P0.09 +#define PIN_D7 (10) // P0.10 +#define PIN_D9 (8) // P0.8 +#define PIN_D10 (11) // P0.11 +#define PIN_D11 (13) // P0.13 +#define PIN_D12 (12) // P0.12 +#define PIN_D13 (14) // P0.14 +#define PIN_D14 (2) // P0.02 +#define PIN_D15 (3) // P0.03 + +static const uint8_t D0 = PIN_D0 ; +static const uint8_t D1 = PIN_D1 ; +static const uint8_t D2 = PIN_D2 ; +static const uint8_t D3 = PIN_D3 ; +static const uint8_t D4 = PIN_D4 ; +static const uint8_t D6 = PIN_D6 ; +static const uint8_t D7 = PIN_D7 ; +static const uint8_t D9 = PIN_D9 ; +static const uint8_t D10 = PIN_D10 ; +static const uint8_t D11 = PIN_D11 ; +static const uint8_t D12 = PIN_D12 ; +static const uint8_t D13 = PIN_D13 ; +static const uint8_t D14 = PIN_D14 ; +static const uint8_t D15 = PIN_D15 ; + +// Other pins +//static const uint8_t AREF = PIN_AREF; + +//#define PIN_AREF (24) +//#define PIN_VBAT PIN_A7 + +/* + * Serial interfaces + */ +//#define PIN_SERIAL_RX (8) //used for original Adafruit Bootloader +//#define PIN_SERIAL_TX (6) //used for original Adafruit Bootloader + +#define PIN_SERIAL_RX (5) // P0.05 +#define PIN_SERIAL_TX (6) // P0.06 +#define PIN_SERIAL_CTS (7) // P0.07 +#define PIN_SERIAL_RTS (31) // P0.31 +#define PIN_SERIAL_DTR (28) // P0.28 +#define PIN_SERIAL_DSR (29) // P0.29 + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (12) // P0.12 +#define PIN_SPI_MOSI (13) // P0.13 +#define PIN_SPI_SCK (14) // P0.14 + +static const uint8_t SS = 11 ; // P0.11 +static const uint8_t MOSI = PIN_SPI_MOSI ; +static const uint8_t MISO = PIN_SPI_MISO ; +static const uint8_t SCK = PIN_SPI_SCK ; + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (2) // P0.02 +#define PIN_WIRE_SCL (3) // P0.03 + +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; + + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + + +#endif //_VARIANT_NINA_B112_UBLOX_ diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B302_ublox/pins_arduino.h b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B302_ublox/pins_arduino.h new file mode 100644 index 0000000..3ef4d4a --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B302_ublox/pins_arduino.h @@ -0,0 +1,17 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 +*/ + +// API compatibility +#include "variant.h" diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B302_ublox/variant.cpp b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B302_ublox/variant.cpp new file mode 100644 index 0000000..b51ac2f --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B302_ublox/variant.cpp @@ -0,0 +1,109 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ +// Thanks to great work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip). +// See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) + +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" +#include "nrf.h" + +const uint32_t g_ADigitalPinMap[] = +{ + // D0 .. D13 + 29, // D0 is P0.29 (UART TX) + 45, // D1 is P1.13 (UART RX + 44, // D2 is P1.12 (NFC2) + 31, // D3 is P0.31 (LED1) + 13, // D4 is P0.13 (LED2) + 11, // D5 is P0.11 + 9, // D6 is P0.09 + 10, // D7 is P0.10 (Button) + 41, // D8 is P1.09 (NeoPixel) + 12, // D9 is P0.12 + 14, // D10 is P0.14 + 15, // D11 is P0.15 + 32, // D12 is P1.00 + 7, // D13 is P0.07 + + // D14 .. D21 (aka A0 .. A7) + 4, // D14 is P0.04 (A0) + 30, // D15 is P0.30 (A1) + 5, // D16 is P0.05 (A2) + 2, // D17 is P0.02 (A3) + 28, // D18 is P0.28 (A4) + 3, // D19 is P0.03 (A5) + 29, // D20 is P0.29 (A6, Battery) ???? + 31, // D21 is P0.31 (A7, ARef) ???? + + // D22 .. D23 (aka I2C pins) + 16, // D22 is P0.16 (SDA) + 24, // D23 is P0.24 (SCL) + + // D24 .. D26 (aka SPI pins) + 32, // D24 is P1.00 (SPI MISO) + 15, // D25 is P0.15 (SPI MOSI) + 7, // D26 is P0.07 (SPI SCK ) + + // QSPI pins (not exposed via any header / test point) + 19, // D27 is P0.19 (QSPI CLK) + 17, // D28 is P0.17 (QSPI CS) + 20, // D29 is P0.20 (QSPI Data 0) + 21, // D30 is P0.21 (QSPI Data 1) + 22, // D31 is P0.22 (QSPI Data 2) + 23, // D32 is P0.23 (QSPI Data 3) + + // The remaining NFC pin + 9, // D33 is P0.09 (NFC1, exposed only via test point on bottom of board) + + // Thus, there are 34 defined pins + + // The remaining pins are not usable: + // + // + // The following pins were never listed as they were considered unusable + // 0, // P0.00 is XL1 (attached to 32.768kHz crystal) + // 1, // P0.01 is XL2 (attached to 32.768kHz crystal) + // 18, // P0.18 is RESET (attached to switch) + // 32, // P1.00 is SWO (attached to debug header) + // + // The remaining pins are not connected (per schematic) + // 33, // P1.01 is not connected per schematic + // 35, // P1.03 is not connected per schematic + // 36, // P1.04 is not connected per schematic + // 37, // P1.05 is not connected per schematic + // 38, // P1.06 is not connected per schematic + // 39, // P1.07 is not connected per schematic + // 43, // P1.11 is not connected per schematic + // 44, // P1.12 is not connected per schematic + // 45, // P1.13 is not connected per schematic + // 46, // P1.14 is not connected per schematic +}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); +} + diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B302_ublox/variant.h b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B302_ublox/variant.h new file mode 100644 index 0000000..a5b7eb9 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.20.5/variants/NINA_B302_ublox/variant.h @@ -0,0 +1,159 @@ + /* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ + +// Thanks to great work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip). +// See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) + +#ifndef _VARIANT_NINA_B302_UBLOX_ +#define _VARIANT_NINA_B302_UBLOX_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus +// (XX) = TABLE INDEX +// Number of pins defined in PinDescription array +#define PINS_COUNT (34) +#define NUM_DIGITAL_PINS (34) +#define NUM_ANALOG_INPUTS (6) // A6 is used for battery, A7 is analog reference +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (3) +#define PIN_LED2 (4) +#define PIN_NEOPIXEL (8) + +#define LED_BUILTIN PIN_LED1 +#define LED_CONN PIN_LED2 + +#define LED_RED PIN_LED1 +#define LED_BLUE PIN_LED2 + +#define LED_STATE_ON 1 // State when LED is litted + +/* + * Buttons + */ +#define PIN_BUTTON1 (7) + +/* + * Analog pins + */ +#define PIN_A0 (14) +#define PIN_A1 (15) +#define PIN_A2 (16) +#define PIN_A3 (17) +#define PIN_A4 (18) +#define PIN_A5 (19) +#define PIN_A6 (20) +#define PIN_A7 (21) + +#define D0 (0) +#define D1 (1) +#define D2 (2) +#define D3 (3) +#define D4 (4) +#define D5 (5) +#define D6 (6) +#define D7 (7) +#define D8 (8) +#define D9 (9) +#define D10 (10) +#define D11 (11) +#define D12 (12) +#define D13 (13) + +static const uint8_t A0 = PIN_A0 ; +static const uint8_t A1 = PIN_A1 ; +static const uint8_t A2 = PIN_A2 ; +static const uint8_t A3 = PIN_A3 ; +static const uint8_t A4 = PIN_A4 ; +static const uint8_t A5 = PIN_A5 ; +static const uint8_t A6 = PIN_A6 ; +static const uint8_t A7 = PIN_A7 ; +#define ADC_RESOLUTION 14 + +// Other pins +#define PIN_AREF PIN_A7 +#define PIN_VBAT PIN_A6 +#define PIN_NFC1 (33) +#define PIN_NFC2 (2) + +static const uint8_t AREF = PIN_AREF; + +/* + * Serial interfaces + */ +#define PIN_SERIAL1_RX (1) +#define PIN_SERIAL1_TX (0) + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (24) //24 original +#define PIN_SPI_MOSI (25) //25 original +#define PIN_SPI_SCK (26) //26 original + +static const uint8_t SS = (13); +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (22) +#define PIN_WIRE_SCL (23) + +// QSPI Pins +#define PIN_QSPI_SCK 27 +#define PIN_QSPI_CS 28 +#define PIN_QSPI_IO0 29 +#define PIN_QSPI_IO1 30 +#define PIN_QSPI_IO2 31 +#define PIN_QSPI_IO3 32 + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES GD25Q16C +#define EXTERNAL_FLASH_USE_QSPI + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif //_VARIANT_NINA_B302_UBLOX_ diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.21.0/boards.txt b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/boards.txt new file mode 100644 index 0000000..762f02f --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/boards.txt @@ -0,0 +1,649 @@ +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# Copyright (c) 2016 Sandeep Mistry All right reserved. +# Copyright (c) 2017 Adafruit Industries. 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 + +menu.softdevice=Bootloader +menu.debug=Debug + +# ---------------------------------- +# Bluefruit Feather nRF52832 +# ---------------------------------- +feather52832.name=Adafruit Feather nRF52832 +feather52832.bootloader.tool=bootburn + +# Upload +feather52832.upload.tool=nrfutil +feather52832.upload.protocol=nrfutil +feather52832.upload.use_1200bps_touch=false +feather52832.upload.wait_for_upload_port=false +feather52832.upload.native_usb=false +feather52832.upload.maximum_size=290816 +feather52832.upload.maximum_data_size=52224 + +# Build +feather52832.build.mcu=cortex-m4 +feather52832.build.f_cpu=64000000 +feather52832.build.board=NRF52832_FEATHER +feather52832.build.core=nRF5 +feather52832.build.variant=feather_nrf52832 +feather52832.build.usb_manufacturer="Adafruit LLC" +feather52832.build.usb_product="Feather nRF52832" +feather52832.build.extra_flags=-DNRF52832_XXAA -DNRF52 +feather52832.build.ldscript=nrf52832_s132_v6.ld + +# SofDevice Menu +feather52832.menu.softdevice.s132v6=0.3.2 SoftDevice s132 6.1.1 +feather52832.menu.softdevice.s132v6.build.sd_name=s132 +feather52832.menu.softdevice.s132v6.build.sd_version=6.1.1 +feather52832.menu.softdevice.s132v6.build.sd_fwid=0x00B7 + +# Debug Menu +feather52832.menu.debug.l0=Level 0 (Release) +feather52832.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +feather52832.menu.debug.l1=Level 1 (Error Message) +feather52832.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +feather52832.menu.debug.l2=Level 2 (Full Debug) +feather52832.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +feather52832.menu.debug.l3=Level 3 (Segger SystemView) +feather52832.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +feather52832.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Bluefruit Feather nRF52840 Express +# ---------------------------------- +feather52840.name=Adafruit Feather nRF52840 Express + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +feather52840.vid.0=0x239A +feather52840.pid.0=0x8029 +feather52840.vid.1=0x239A +feather52840.pid.1=0x0029 +feather52840.vid.2=0x239A +feather52840.pid.2=0x002A +feather52840.vid.3=0x239A +feather52840.pid.3=0x802A + +# Upload +feather52840.bootloader.tool=bootburn +feather52840.upload.tool=nrfutil +feather52840.upload.protocol=nrfutil +feather52840.upload.use_1200bps_touch=true +feather52840.upload.wait_for_upload_port=true +feather52840.upload.maximum_size=815104 +feather52840.upload.maximum_data_size=237568 + +# Build +feather52840.build.mcu=cortex-m4 +feather52840.build.f_cpu=64000000 +feather52840.build.board=NRF52840_FEATHER +feather52840.build.core=nRF5 +feather52840.build.variant=feather_nrf52840_express +feather52840.build.usb_manufacturer="Adafruit LLC" +feather52840.build.usb_product="Feather nRF52840 Express" +feather52840.build.extra_flags=-DNRF52840_XXAA {build.flags.usb} +feather52840.build.ldscript=nrf52840_s140_v6.ld +feather52840.build.vid=0x239A +feather52840.build.pid=0x8029 + +# SofDevice Menu +feather52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +feather52840.menu.softdevice.s140v6.build.sd_name=s140 +feather52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +feather52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +feather52840.menu.debug.l0=Level 0 (Release) +feather52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +feather52840.menu.debug.l1=Level 1 (Error Message) +feather52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +feather52840.menu.debug.l2=Level 2 (Full Debug) +feather52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +feather52840.menu.debug.l3=Level 3 (Segger SystemView) +feather52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +feather52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + +# ---------------------------------- +# Feather Bluefruit sense +# ---------------------------------- +feather52840sense.name=Adafruit Feather Bluefruit Sense + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +feather52840sense.vid.0=0x239A +feather52840sense.pid.0=0x8087 +feather52840sense.vid.1=0x239A +feather52840sense.pid.1=0x0087 +feather52840sense.vid.2=0x239A +feather52840sense.pid.2=0x0088 +feather52840sense.vid.3=0x239A +feather52840sense.pid.3=0x8088 + +# Upload +feather52840sense.bootloader.tool=bootburn +feather52840sense.upload.tool=nrfutil +feather52840sense.upload.protocol=nrfutil +feather52840sense.upload.use_1200bps_touch=true +feather52840sense.upload.wait_for_upload_port=true +feather52840sense.upload.maximum_size=815104 +feather52840sense.upload.maximum_data_size=237568 + +# Build +feather52840sense.build.mcu=cortex-m4 +feather52840sense.build.f_cpu=64000000 +feather52840sense.build.board=NRF52840_FEATHER_SENSE +feather52840sense.build.core=nRF5 +feather52840sense.build.variant=feather_nrf52840_sense +feather52840sense.build.usb_manufacturer="Adafruit LLC" +feather52840sense.build.usb_product="Feather nRF52840 Sense" +feather52840sense.build.extra_flags=-DNRF52840_XXAA {build.flags.usb} +feather52840sense.build.ldscript=nrf52840_s140_v6.ld +feather52840sense.build.vid=0x239A +feather52840sense.build.pid=0x8087 + +# SofDevice Menu +feather52840sense.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +feather52840sense.menu.softdevice.s140v6.build.sd_name=s140 +feather52840sense.menu.softdevice.s140v6.build.sd_version=6.1.1 +feather52840sense.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +feather52840sense.menu.debug.l0=Level 0 (Release) +feather52840sense.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +feather52840sense.menu.debug.l1=Level 1 (Error Message) +feather52840sense.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +feather52840sense.menu.debug.l2=Level 2 (Full Debug) +feather52840sense.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +feather52840sense.menu.debug.l3=Level 3 (Segger SystemView) +feather52840sense.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +feather52840sense.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + +# --------------------------------------------- +# Bluefruit ItsyBitsy nRF52840 Express +# --------------------------------------------- +itsybitsy52840.name=Adafruit ItsyBitsy nRF52840 Express + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +itsybitsy52840.vid.0=0x239A +itsybitsy52840.pid.0=0x8051 +itsybitsy52840.vid.1=0x239A +itsybitsy52840.pid.1=0x0051 +itsybitsy52840.vid.2=0x239A +itsybitsy52840.pid.2=0x0052 +itsybitsy52840.vid.3=0x239A +itsybitsy52840.pid.3=0x8052 + +# Upload +itsybitsy52840.bootloader.tool=bootburn +itsybitsy52840.upload.tool=nrfutil +itsybitsy52840.upload.protocol=nrfutil +itsybitsy52840.upload.use_1200bps_touch=true +itsybitsy52840.upload.wait_for_upload_port=true +itsybitsy52840.upload.maximum_size=815104 +itsybitsy52840.upload.maximum_data_size=237568 + +# Build +itsybitsy52840.build.mcu=cortex-m4 +itsybitsy52840.build.f_cpu=64000000 +itsybitsy52840.build.board=NRF52840_ITSYBITSY +itsybitsy52840.build.core=nRF5 +itsybitsy52840.build.variant=itsybitsy_nrf52840_express +itsybitsy52840.build.usb_manufacturer="Adafruit LLC" +itsybitsy52840.build.usb_product="ItsyBitsy nRF52840 Express" +itsybitsy52840.build.extra_flags=-DNRF52840_XXAA -DARDUINO_NRF52_ITSYBITSY {build.flags.usb} +itsybitsy52840.build.ldscript=nrf52840_s140_v6.ld +itsybitsy52840.build.vid=0x239A +itsybitsy52840.build.pid=0x8051 + +# SofDevice Menu +itsybitsy52840.menu.softdevice.s140v6=0.2.11 SoftDevice s140 6.1.1 +itsybitsy52840.menu.softdevice.s140v6.build.sd_name=s140 +itsybitsy52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +itsybitsy52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +itsybitsy52840.menu.debug.l0=Level 0 (Release) +itsybitsy52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +itsybitsy52840.menu.debug.l1=Level 1 (Error Message) +itsybitsy52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +itsybitsy52840.menu.debug.l2=Level 2 (Full Debug) +itsybitsy52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +itsybitsy52840.menu.debug.l3=Level 3 (Segger SystemView) +itsybitsy52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +itsybitsy52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# --------------------------------------------- +# Bluefruit Circuit Playground nRF52840 Express +# --------------------------------------------- +cplaynrf52840.name=Adafruit Circuit Playground Bluefruit + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +cplaynrf52840.vid.0=0x239A +cplaynrf52840.pid.0=0x8045 +cplaynrf52840.vid.1=0x239A +cplaynrf52840.pid.1=0x0045 +cplaynrf52840.vid.2=0x239A +cplaynrf52840.pid.2=0x0046 +cplaynrf52840.vid.3=0x239A +cplaynrf52840.pid.3=0x8046 + +# Upload +cplaynrf52840.bootloader.tool=bootburn +cplaynrf52840.upload.tool=nrfutil +cplaynrf52840.upload.protocol=nrfutil +cplaynrf52840.upload.use_1200bps_touch=true +cplaynrf52840.upload.wait_for_upload_port=true +cplaynrf52840.upload.maximum_size=815104 +cplaynrf52840.upload.maximum_data_size=237568 + +# Build +cplaynrf52840.build.mcu=cortex-m4 +cplaynrf52840.build.f_cpu=64000000 +cplaynrf52840.build.board=NRF52840_CIRCUITPLAY +cplaynrf52840.build.core=nRF5 +cplaynrf52840.build.variant=circuitplayground_nrf52840 +cplaynrf52840.build.usb_manufacturer="Adafruit LLC" +cplaynrf52840.build.usb_product="Circuit Playground Bluefruit" +cplaynrf52840.build.extra_flags=-DNRF52840_XXAA {build.flags.usb} +cplaynrf52840.build.ldscript=nrf52840_s140_v6.ld +cplaynrf52840.build.vid=0x239A +cplaynrf52840.build.pid=0x8045 + +# SofDevice Menu +cplaynrf52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +cplaynrf52840.menu.softdevice.s140v6.build.sd_name=s140 +cplaynrf52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +cplaynrf52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +cplaynrf52840.menu.debug.l0=Level 0 (Release) +cplaynrf52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +cplaynrf52840.menu.debug.l1=Level 1 (Error Message) +cplaynrf52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +cplaynrf52840.menu.debug.l2=Level 2 (Full Debug) +cplaynrf52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +cplaynrf52840.menu.debug.l3=Level 3 (Segger SystemView) +cplaynrf52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +cplaynrf52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + +# --------------------------------------------- +# Clue nRF52840 +# --------------------------------------------- +cluenrf52840.name=Adafruit CLUE + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +cluenrf52840.vid.0=0x239A +cluenrf52840.pid.0=0x8072 +cluenrf52840.vid.1=0x239A +cluenrf52840.pid.1=0x0072 +cluenrf52840.vid.2=0x239A +cluenrf52840.pid.2=0x0071 +cluenrf52840.vid.3=0x239A +cluenrf52840.pid.3=0x8071 + +# Upload +cluenrf52840.bootloader.tool=bootburn +cluenrf52840.upload.tool=nrfutil +cluenrf52840.upload.protocol=nrfutil +cluenrf52840.upload.use_1200bps_touch=true +cluenrf52840.upload.wait_for_upload_port=true +cluenrf52840.upload.maximum_size=815104 +cluenrf52840.upload.maximum_data_size=237568 + +# Build +cluenrf52840.build.mcu=cortex-m4 +cluenrf52840.build.f_cpu=64000000 +cluenrf52840.build.board=NRF52840_CLUE +cluenrf52840.build.core=nRF5 +cluenrf52840.build.variant=clue_nrf52840 +cluenrf52840.build.usb_manufacturer="Adafruit LLC" +cluenrf52840.build.usb_product="CLUE" +cluenrf52840.build.extra_flags=-DNRF52840_XXAA {build.flags.usb} +cluenrf52840.build.ldscript=nrf52840_s140_v6.ld +cluenrf52840.build.vid=0x239A +cluenrf52840.build.pid=0x8071 + +# SofDevice Menu +cluenrf52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +cluenrf52840.menu.softdevice.s140v6.build.sd_name=s140 +cluenrf52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +cluenrf52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +cluenrf52840.menu.debug.l0=Level 0 (Release) +cluenrf52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +cluenrf52840.menu.debug.l1=Level 1 (Error Message) +cluenrf52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +cluenrf52840.menu.debug.l2=Level 2 (Full Debug) +cluenrf52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +cluenrf52840.menu.debug.l3=Level 3 (Segger SystemView) +cluenrf52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +cluenrf52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Bluefruit Metro nRF52840 Express +# ---------------------------------- +metro52840.name=Adafruit Bluefruit Metro nRF52840 Express + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +metro52840.vid.0=0x239A +metro52840.pid.0=0x803F +metro52840.vid.1=0x239A +metro52840.pid.1=0x003F +metro52840.vid.2=0x239A +metro52840.pid.2=0x0040 +metro52840.vid.3=0x239A +metro52840.pid.3=0x8040 + +# Upload +metro52840.bootloader.tool=bootburn +metro52840.upload.tool=nrfutil +metro52840.upload.protocol=nrfutil +metro52840.upload.use_1200bps_touch=true +metro52840.upload.wait_for_upload_port=true +metro52840.upload.maximum_size=815104 +metro52840.upload.maximum_data_size=237568 + +# Build +metro52840.build.mcu=cortex-m4 +metro52840.build.f_cpu=64000000 +metro52840.build.board=NRF52840_METRO +metro52840.build.core=nRF5 +metro52840.build.variant=metro_nrf52840_express +metro52840.build.usb_manufacturer="Adafruit LLC" +metro52840.build.usb_product="Metro nRF52840 Express" +metro52840.build.extra_flags=-DNRF52840_XXAA {build.flags.usb} +metro52840.build.ldscript=nrf52840_s140_v6.ld +metro52840.build.vid=0x239A +metro52840.build.pid=0x803F + +# SofDevice Menu +metro52840.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +metro52840.menu.softdevice.s140v6.build.sd_name=s140 +metro52840.menu.softdevice.s140v6.build.sd_version=6.1.1 +metro52840.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +metro52840.menu.debug.l0=Level 0 (Release) +metro52840.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +metro52840.menu.debug.l1=Level 1 (Error Message) +metro52840.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +metro52840.menu.debug.l2=Level 2 (Full Debug) +metro52840.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +metro52840.menu.debug.l3=Level 3 (Segger SystemView) +metro52840.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +metro52840.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + + + + +# ------------------------------------------------------- +# +# Boards that aren't made by Adafruit +# +# ------------------------------------------------------- + + +# ---------------------------------- +# Nordic nRF52840DK (PCA10056) +# ---------------------------------- +pca10056.name=Nordic nRF52840DK (PCA10056) +pca10056.bootloader.tool=bootburn + +# Upload +pca10056.upload.tool=nrfutil +pca10056.upload.protocol=nrfutil +pca10056.upload.use_1200bps_touch=true +pca10056.upload.wait_for_upload_port=true +pca10056.upload.maximum_size=815104 +pca10056.upload.maximum_data_size=237568 + +# Build +pca10056.build.mcu=cortex-m4 +pca10056.build.f_cpu=64000000 +pca10056.build.board=NRF52840_PCA10056 +pca10056.build.core=nRF5 +pca10056.build.variant=pca10056 +pca10056.build.usb_manufacturer="Nordic" +pca10056.build.usb_product="nRF52840 DK" +pca10056.build.extra_flags=-DNRF52840_XXAA {build.flags.usb} +pca10056.build.ldscript=nrf52840_s140_v6.ld +pca10056.build.vid=0x239A +pca10056.build.pid=0x8029 + +# SofDevice Menu +pca10056.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +pca10056.menu.softdevice.s140v6.build.sd_name=s140 +pca10056.menu.softdevice.s140v6.build.sd_version=6.1.1 +pca10056.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +pca10056.menu.debug.l0=Level 0 (Release) +pca10056.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +pca10056.menu.debug.l1=Level 1 (Error Message) +pca10056.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +pca10056.menu.debug.l2=Level 2 (Full Debug) +pca10056.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +pca10056.menu.debug.l3=Level 3 (Segger SystemView) +pca10056.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +pca10056.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Particle Xenon +# ---------------------------------- +particle_xenon.name=Particle Xenon + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +particle_xenon.vid.0=0x239A +particle_xenon.pid.0=0x8029 +particle_xenon.vid.1=0x239A +particle_xenon.pid.1=0x0029 +particle_xenon.vid.2=0x239A +particle_xenon.pid.2=0x002A +particle_xenon.vid.3=0x239A +particle_xenon.pid.3=0x802A + +# Upload +particle_xenon.bootloader.tool=bootburn +particle_xenon.upload.tool=nrfutil +particle_xenon.upload.protocol=nrfutil +particle_xenon.upload.use_1200bps_touch=true +particle_xenon.upload.wait_for_upload_port=true +particle_xenon.upload.maximum_size=815104 +particle_xenon.upload.maximum_data_size=237568 + +# Build +particle_xenon.build.mcu=cortex-m4 +particle_xenon.build.f_cpu=64000000 +particle_xenon.build.board=PARTICLE_XENON +particle_xenon.build.core=nRF5 +particle_xenon.build.variant=particle_xenon +particle_xenon.build.usb_manufacturer="Particle Industries" +particle_xenon.build.usb_product="Particle Xenon" +particle_xenon.build.extra_flags=-DNRF52840_XXAA {build.flags.usb} +particle_xenon.build.ldscript=nrf52840_s140_v6.ld +particle_xenon.build.vid=0x239A +particle_xenon.build.pid=0x8029 + +# SofDevice Menu +particle_xenon.menu.softdevice.s140v6=0.2.11 SoftDevice s140 6.1.1 +particle_xenon.menu.softdevice.s140v6.build.sd_name=s140 +particle_xenon.menu.softdevice.s140v6.build.sd_version=6.1.1 +particle_xenon.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +particle_xenon.menu.debug.l0=Level 0 (Release) +particle_xenon.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +particle_xenon.menu.debug.l1=Level 1 (Error Message) +particle_xenon.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +particle_xenon.menu.debug.l2=Level 2 (Full Debug) +particle_xenon.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +particle_xenon.menu.debug.l3=Level 3 (Segger SystemView) +particle_xenon.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +particle_xenon.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# Raytac MDBT50Q - RX +# ---------------------------------- +mdbt50qrx.name=Raytac MDBT50Q-RX Dongle + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +mdbt50qrx.vid.0=0x239A +mdbt50qrx.pid.0=0x8029 +mdbt50qrx.vid.1=0x239A +mdbt50qrx.pid.1=0x0029 +mdbt50qrx.vid.2=0x239A +mdbt50qrx.pid.2=0x002A +mdbt50qrx.vid.3=0x239A +mdbt50qrx.pid.3=0x802A + +# Upload +mdbt50qrx.bootloader.tool=bootburn +mdbt50qrx.upload.tool=nrfutil +mdbt50qrx.upload.protocol=nrfutil +mdbt50qrx.upload.use_1200bps_touch=true +mdbt50qrx.upload.wait_for_upload_port=true +mdbt50qrx.upload.maximum_size=815104 +mdbt50qrx.upload.maximum_data_size=237568 + +# Build +mdbt50qrx.build.mcu=cortex-m4 +mdbt50qrx.build.f_cpu=64000000 +mdbt50qrx.build.board=MDBT50Q_RX +mdbt50qrx.build.core=nRF5 +mdbt50qrx.build.variant=raytac_mdbt50q_rx +mdbt50qrx.build.usb_manufacturer="Raytac Corporation" +mdbt50qrx.build.usb_product="Raytac MDBT50Q - RX" +mdbt50qrx.build.extra_flags=-DNRF52840_XXAA {build.flags.usb} +mdbt50qrx.build.ldscript=nrf52840_s140_v6.ld +mdbt50qrx.build.vid=0x239A +mdbt50qrx.build.pid=0x8029 + +# SofDevice Menu +mdbt50qrx.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +mdbt50qrx.menu.softdevice.s140v6.build.sd_name=s140 +mdbt50qrx.menu.softdevice.s140v6.build.sd_version=6.1.1 +mdbt50qrx.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +mdbt50qrx.menu.debug.l0=Level 0 (Release) +mdbt50qrx.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +mdbt50qrx.menu.debug.l1=Level 1 (Error Message) +mdbt50qrx.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +mdbt50qrx.menu.debug.l2=Level 2 (Full Debug) +mdbt50qrx.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +mdbt50qrx.menu.debug.l3=Level 3 (Segger SystemView) +mdbt50qrx.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +mdbt50qrx.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# NINA B302 +# ---------------------------------- +ninab302.name=NINA B302 ublox + +# VID/PID for bootloader with/without UF2, Arduino + Circuitpython App +ninab302.vid.0=0x239A +ninab302.pid.0=0x8029 +ninab302.vid.1=0x239A +ninab302.pid.1=0x0029 +ninab302.vid.2=0x7239A +ninab302.pid.2=0x002A +ninab302.vid.3=0x239A +ninab302.pid.3=0x802A + +# Upload +ninab302.bootloader.tool=bootburn +ninab302.upload.tool=nrfutil +ninab302.upload.protocol=nrfutil +ninab302.upload.use_1200bps_touch=true +ninab302.upload.wait_for_upload_port=true +ninab302.upload.maximum_size=815104 +ninab302.upload.maximum_data_size=237568 + +# Build +ninab302.build.mcu=cortex-m4 +ninab302.build.f_cpu=64000000 +ninab302.build.board=NINA_B302_ublox +ninab302.build.core=nRF5 +ninab302.build.variant=NINA_B302_ublox +ninab302.build.usb_manufacturer="Nordic" +ninab302.build.usb_product="NINA B302 ublox" +ninab302.build.extra_flags=-DNRF52840_XXAA -DNINA_B302_ublox {build.flags.usb} +ninab302.build.ldscript=nrf52840_s140_v6.ld +ninab302.build.vid=0x239A +ninab302.build.pid=0x8029 + +# SofDevice Menu +ninab302.menu.softdevice.s140v6=0.3.2 SoftDevice s140 6.1.1 +ninab302.menu.softdevice.s140v6.build.sd_name=s140 +ninab302.menu.softdevice.s140v6.build.sd_version=6.1.1 +ninab302.menu.softdevice.s140v6.build.sd_fwid=0x00B6 + +# Debug Menu +ninab302.menu.debug.l0=Level 0 (Release) +ninab302.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +ninab302.menu.debug.l1=Level 1 (Error Message) +ninab302.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +ninab302.menu.debug.l2=Level 2 (Full Debug) +ninab302.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +ninab302.menu.debug.l3=Level 3 (Segger SystemView) +ninab302.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +ninab302.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 + +# ---------------------------------- +# NINA B112 +# ---------------------------------- +ninab112.name=NINA B112 ublox +ninab112.bootloader.tool=bootburn + +# Upload +ninab112.upload.tool=nrfutil +ninab112.upload.protocol=nrfutil +ninab112.upload.use_1200bps_touch=false +ninab112.upload.wait_for_upload_port=false +ninab112.upload.native_usb=false +ninab112.upload.maximum_size=290816 +ninab112.upload.maximum_data_size=52224 + +# Build +ninab112.build.mcu=cortex-m4 +ninab112.build.f_cpu=64000000 +ninab112.build.board=NINA_B112_ublox +ninab112.build.core=nRF5 +ninab112.build.variant=NINA_B112_ublox +feather52840.build.usb_manufacturer="Adafruit LLC" +feather52840.build.usb_product="Feather nRF52832" +ninab112.build.extra_flags=-DNRF52832_XXAA -DNINA_B112_ublox -DNRF52 +ninab112.build.ldscript=nrf52832_s132_v6.ld + +# SofDevice Menu +ninab112.menu.softdevice.s132v6=0.3.2 SoftDevice s132 6.1.1 +ninab112.menu.softdevice.s132v6.build.sd_name=s132 +ninab112.menu.softdevice.s132v6.build.sd_version=6.1.1 +ninab112.menu.softdevice.s132v6.build.sd_fwid=0x00B7 + +# Debug Menu +ninab112.menu.debug.l0=Level 0 (Release) +ninab112.menu.debug.l0.build.debug_flags=-DCFG_DEBUG=0 +ninab112.menu.debug.l1=Level 1 (Error Message) +ninab112.menu.debug.l1.build.debug_flags=-DCFG_DEBUG=1 +ninab112.menu.debug.l2=Level 2 (Full Debug) +ninab112.menu.debug.l2.build.debug_flags=-DCFG_DEBUG=2 +ninab112.menu.debug.l3=Level 3 (Segger SystemView) +ninab112.menu.debug.l3.build.debug_flags=-DCFG_DEBUG=3 +ninab112.menu.debug.l3.build.sysview_flags=-DCFG_SYSVIEW=1 diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.21.0/cores/nRF5/Udp.h b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/cores/nRF5/Udp.h new file mode 100644 index 0000000..cc814d3 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/cores/nRF5/Udp.h @@ -0,0 +1,92 @@ +/* + * Udp.cpp: Library to send/receive UDP packets. + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef udp_h +#define udp_h + +#include +#include + +class UDP : public Stream { + +public: + virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + + // KH, add virtual function to support Multicast, necessary for many services (MDNS, UPnP, etc.) + virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure + + virtual void stop() =0; // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port) =0; + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port) =0; + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket() =0; + // Write a single byte into the packet + virtual size_t write(uint8_t) =0; + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size) =0; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket() =0; + // Number of bytes remaining in the current packet + virtual int available() =0; + // Read a single byte from the current packet + virtual int read() =0; + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len) =0; + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) =0; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek() =0; + virtual void flush() =0; // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() =0; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() =0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.21.0/platform.txt b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/platform.txt new file mode 100644 index 0000000..3de4b45 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/platform.txt @@ -0,0 +1,164 @@ +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# Copyright (c) 2016 Sandeep Mistry All right reserved. +# Copyright (c) 2017 Adafruit Industries. All rights reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +name=Adafruit nRF52 Boards +version=0.21.0 + +# Compile variables +# ----------------- + +compiler.warning_flags=-w +compiler.warning_flags.none=-w +compiler.warning_flags.default= +compiler.warning_flags.more=-Wall +compiler.warning_flags.all=-Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wno-pointer-arith + +# Allow changing optimization settings via platform.local.txt / boards.local.txt +compiler.optimization_flag=-Ofast + +compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ +compiler.c.cmd=arm-none-eabi-gcc +compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD + +# KH, Error here to use gcc, must use g++ +#compiler.c.elf.cmd=arm-none-eabi-gcc +compiler.c.elf.cmd=arm-none-eabi-g++ + +compiler.c.elf.flags={compiler.optimization_flag} -Wl,--gc-sections -save-temps +compiler.S.cmd=arm-none-eabi-gcc +compiler.S.flags=-c -g -x assembler-with-cpp +compiler.cpp.cmd=arm-none-eabi-g++ +compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD +compiler.ar.cmd=arm-none-eabi-ar +compiler.ar.flags=rcs +compiler.objcopy.cmd=arm-none-eabi-objcopy +compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 +compiler.elf2bin.flags=-O binary +compiler.elf2bin.cmd=arm-none-eabi-objcopy +compiler.elf2hex.flags=-O ihex +compiler.elf2hex.cmd=arm-none-eabi-objcopy +compiler.ldflags=-mcpu={build.mcu} -mthumb {build.float_flags} -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align --specs=nano.specs --specs=nosys.specs +compiler.size.cmd=arm-none-eabi-size + +# this can be overriden in boards.txt +build.float_flags=-mfloat-abi=hard -mfpu=fpv4-sp-d16 -u _printf_float +build.debug_flags=-DCFG_DEBUG=0 +build.logger_flags=-DCFG_LOGGER=1 +build.sysview_flags=-DCFG_SYSVIEW=0 + +# common compiler for nrf +rtos.path={build.core.path}/freertos +nordic.path={build.core.path}/nordic + +# build.logger_flags and build.sysview_flags and intentionally empty, +# to allow modification via a user's own boards.local.txt or platform.local.txt files. +build.flags.nrf= -DSOFTDEVICE_PRESENT -DARDUINO_NRF52_ADAFRUIT -DNRF52_SERIES -DLFS_NAME_MAX=64 {compiler.optimization_flag} {build.debug_flags} {build.logger_flags} {build.sysview_flags} "-I{build.core.path}/cmsis/Core/Include" "-I{nordic.path}" "-I{nordic.path}/nrfx" "-I{nordic.path}/nrfx/hal" "-I{nordic.path}/nrfx/mdk" "-I{nordic.path}/nrfx/soc" "-I{nordic.path}/nrfx/drivers/include" "-I{nordic.path}/nrfx/drivers/src" "-I{nordic.path}/softdevice/{build.sd_name}_nrf52_{build.sd_version}_API/include" "-I{nordic.path}/softdevice/{build.sd_name}_nrf52_{build.sd_version}_API/include/nrf52" "-I{rtos.path}/Source/include" "-I{rtos.path}/config" "-I{rtos.path}/portable/GCC/nrf52" "-I{rtos.path}/portable/CMSIS/nrf52" "-I{build.core.path}/sysview/SEGGER" "-I{build.core.path}/sysview/Config" "-I{build.core.path}/TinyUSB" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore/tinyusb/src" + +# usb flags +build.flags.usb= -DUSBCON -DUSE_TINYUSB -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' + +# These can be overridden in platform.local.txt +compiler.c.extra_flags= +compiler.c.elf.extra_flags= +compiler.cpp.extra_flags= +compiler.S.extra_flags= +compiler.ar.extra_flags= +compiler.libraries.ldflags= +compiler.elf2bin.extra_flags= +compiler.elf2hex.extra_flags= + + +# Compile patterns +# ---------------- + +## Compile c files +## KH Add -DBOARD_NAME="{build.board}" +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.c.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +## Compile c++ files +## KH Add -DBOARD_NAME="{build.board}" +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} '-DARDUINO_BSP_VERSION="{version}"' {compiler.cpp.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +## Compile S files +## KH Add -DBOARD_NAME="{build.board}" +recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.flags.nrf} {includes} "{source_file}" -o "{object_file}" + +## Create archives +recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" + +## Combine gc-sections, archives, and objects +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-L{build.core.path}/linker" "-T{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} {compiler.libraries.ldflags} -Wl,--start-group -lm "{build.path}/{archive_file}" -Wl,--end-group + +## Create output (bin file) +#recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2bin.cmd}" {compiler.elf2bin.flags} {compiler.elf2bin.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" + +## Create output (hex file) +recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" + +## Create dfu package zip file +recipe.objcopy.zip.pattern="{tools.nrfutil.cmd}" dfu genpkg --dev-type 0x0052 --sd-req {build.sd_fwid} --application "{build.path}/{build.project_name}.hex" "{build.path}/{build.project_name}.zip" + +## Create uf2 file +#recipe.objcopy.uf2.pattern=python "{runtime.platform.path}/tools/uf2conv/uf2conv.py" -f 0xADA52840 -c -o "{build.path}/{build.project_name}.uf2" "{build.path}/{build.project_name}.hex" + +## Save bin +recipe.output.tmp_file_bin={build.project_name}.bin +recipe.output.save_file_bin={build.project_name}.save.bin + +## Save hex +recipe.output.tmp_file_hex={build.project_name}.hex +recipe.output.save_file_hexu={build.project_name}.save.hex + +## Compute size +recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" +recipe.size.regex=^(?:\.text|\.data|)\s+([0-9]+).* +recipe.size.regex.data=^(?:\.data|\.bss)\s+([0-9]+).* + +## Export Compiled Binary +recipe.output.tmp_file={build.project_name}.hex +recipe.output.save_file={build.project_name}.{build.variant}.hex + +#*************************************************** +# adafruit-nrfutil for uploading +# https://github.com/adafruit/Adafruit_nRF52_nrfutil +# pre-built binaries are provided for macos and windows +#*************************************************** +tools.nrfutil.cmd=adafruit-nrfutil +tools.nrfutil.cmd.windows={runtime.platform.path}/tools/adafruit-nrfutil/win32/adafruit-nrfutil.exe +tools.nrfutil.cmd.macosx={runtime.platform.path}/tools/adafruit-nrfutil/macos/adafruit-nrfutil + +tools.nrfutil.upload.params.verbose=--verbose +tools.nrfutil.upload.params.quiet= +tools.nrfutil.upload.pattern="{cmd}" {upload.verbose} dfu serial -pkg "{build.path}/{build.project_name}.zip" -p {serial.port} -b 115200 --singlebank + +#*************************************************** +# Burning bootloader with either jlink or nrfutil +#*************************************************** + +# Bootloader version +tools.bootburn.bootloader.file={runtime.platform.path}/bootloader/{build.variant}/{build.variant}_bootloader-0.3.2_{build.sd_name}_{build.sd_version} + +tools.bootburn.bootloader.params.verbose= +tools.bootburn.bootloader.params.quiet= +tools.bootburn.bootloader.pattern={program.burn_pattern} + +# erase flash page while programming +tools.bootburn.erase.params.verbose= +tools.bootburn.erase.params.quiet= +tools.bootburn.erase.pattern= + diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/pins_arduino.h b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/pins_arduino.h new file mode 100644 index 0000000..3ef4d4a --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/pins_arduino.h @@ -0,0 +1,17 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 +*/ + +// API compatibility +#include "variant.h" diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/variant.cpp b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/variant.cpp new file mode 100644 index 0000000..a68820c --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/variant.cpp @@ -0,0 +1,62 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ +// Thanks to great work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip). +// See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) + +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" +#include "nrf.h" + +const uint32_t g_ADigitalPinMap[] = { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31 + }; + diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/variant.h b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/variant.h new file mode 100644 index 0000000..42c7791 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/variant.h @@ -0,0 +1,173 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ + +#ifndef _VARIANT_NINA_B112_UBLOX_ +#define _VARIANT_NINA_B112_UBLOX_ + +#define NRF_CLOCK_LFCLKSRC {.source = NRF_CLOCK_LF_SRC_XTAL, \ + .rc_ctiv = 0, \ +.rc_temp_ctiv = 0, \ +.xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM} + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (32u) +#define NUM_DIGITAL_PINS (32u) +#define NUM_ANALOG_INPUTS (6u) +#define NUM_ANALOG_OUTPUTS (0u) + +// LEDs +#define PIN_LED LED1 +#define LED_BUILTIN PIN_LED + +//LEDs onboard +#define LED1 (8) // Red +#define LED2 (16) // Green/SW1 +#define LED3 (18) // Blue + +#define LED_STATE_ON 1 // State when LED is litted + +//Switch + +#define SW1 (16) +#define SW2 (30) + +// NFC +#define PIN_NFC_1 (9) // P0.9 +#define PIN_NFC_2 (10) // P0.10 + +/* + * Analog pins + */ +#define PIN_A0 (3) // P0.03 +#define PIN_A1 (2) // P0.02 +#define PIN_A2 (4) // P0.04 +#define PIN_A3 (30) // P0.30 +#define PIN_A4 (29) // P0.29 +#define PIN_A5 (28) // P0.28 + +static const uint8_t A0 = PIN_A0 ; +static const uint8_t A1 = PIN_A1 ; +static const uint8_t A2 = PIN_A2 ; +static const uint8_t A3 = PIN_A3 ; +static const uint8_t A4 = PIN_A4 ; +static const uint8_t A5 = PIN_A5 ; + +#define ADC_RESOLUTION 14 + +#define PIN_D0 (5) // P0.05 +#define PIN_D1 (6) // P0.06 +#define PIN_D2 (7) // P0.07 +#define PIN_D3 (31) // P0.31 +#define PIN_D4 (18) // P0.18 +#define PIN_D6 (9) // P0.09 +#define PIN_D7 (10) // P0.10 +#define PIN_D9 (8) // P0.8 +#define PIN_D10 (11) // P0.11 +#define PIN_D11 (13) // P0.13 +#define PIN_D12 (12) // P0.12 +#define PIN_D13 (14) // P0.14 +#define PIN_D14 (2) // P0.02 +#define PIN_D15 (3) // P0.03 + +static const uint8_t D0 = PIN_D0 ; +static const uint8_t D1 = PIN_D1 ; +static const uint8_t D2 = PIN_D2 ; +static const uint8_t D3 = PIN_D3 ; +static const uint8_t D4 = PIN_D4 ; +static const uint8_t D6 = PIN_D6 ; +static const uint8_t D7 = PIN_D7 ; +static const uint8_t D9 = PIN_D9 ; +static const uint8_t D10 = PIN_D10 ; +static const uint8_t D11 = PIN_D11 ; +static const uint8_t D12 = PIN_D12 ; +static const uint8_t D13 = PIN_D13 ; +static const uint8_t D14 = PIN_D14 ; +static const uint8_t D15 = PIN_D15 ; + +// Other pins +//static const uint8_t AREF = PIN_AREF; + +//#define PIN_AREF (24) +//#define PIN_VBAT PIN_A7 + +/* + * Serial interfaces + */ +//#define PIN_SERIAL_RX (8) //used for original Adafruit Bootloader +//#define PIN_SERIAL_TX (6) //used for original Adafruit Bootloader + +#define PIN_SERIAL_RX (5) // P0.05 +#define PIN_SERIAL_TX (6) // P0.06 +#define PIN_SERIAL_CTS (7) // P0.07 +#define PIN_SERIAL_RTS (31) // P0.31 +#define PIN_SERIAL_DTR (28) // P0.28 +#define PIN_SERIAL_DSR (29) // P0.29 + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (12) // P0.12 +#define PIN_SPI_MOSI (13) // P0.13 +#define PIN_SPI_SCK (14) // P0.14 + +static const uint8_t SS = 11 ; // P0.11 +static const uint8_t MOSI = PIN_SPI_MOSI ; +static const uint8_t MISO = PIN_SPI_MISO ; +static const uint8_t SCK = PIN_SPI_SCK ; + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (2) // P0.02 +#define PIN_WIRE_SCL (3) // P0.03 + +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; + + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + + +#endif //_VARIANT_NINA_B112_UBLOX_ diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/pins_arduino.h b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/pins_arduino.h new file mode 100644 index 0000000..3ef4d4a --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/pins_arduino.h @@ -0,0 +1,17 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 +*/ + +// API compatibility +#include "variant.h" diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/variant.cpp b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/variant.cpp new file mode 100644 index 0000000..b51ac2f --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/variant.cpp @@ -0,0 +1,109 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ +// Thanks to great work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip). +// See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) + +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" +#include "nrf.h" + +const uint32_t g_ADigitalPinMap[] = +{ + // D0 .. D13 + 29, // D0 is P0.29 (UART TX) + 45, // D1 is P1.13 (UART RX + 44, // D2 is P1.12 (NFC2) + 31, // D3 is P0.31 (LED1) + 13, // D4 is P0.13 (LED2) + 11, // D5 is P0.11 + 9, // D6 is P0.09 + 10, // D7 is P0.10 (Button) + 41, // D8 is P1.09 (NeoPixel) + 12, // D9 is P0.12 + 14, // D10 is P0.14 + 15, // D11 is P0.15 + 32, // D12 is P1.00 + 7, // D13 is P0.07 + + // D14 .. D21 (aka A0 .. A7) + 4, // D14 is P0.04 (A0) + 30, // D15 is P0.30 (A1) + 5, // D16 is P0.05 (A2) + 2, // D17 is P0.02 (A3) + 28, // D18 is P0.28 (A4) + 3, // D19 is P0.03 (A5) + 29, // D20 is P0.29 (A6, Battery) ???? + 31, // D21 is P0.31 (A7, ARef) ???? + + // D22 .. D23 (aka I2C pins) + 16, // D22 is P0.16 (SDA) + 24, // D23 is P0.24 (SCL) + + // D24 .. D26 (aka SPI pins) + 32, // D24 is P1.00 (SPI MISO) + 15, // D25 is P0.15 (SPI MOSI) + 7, // D26 is P0.07 (SPI SCK ) + + // QSPI pins (not exposed via any header / test point) + 19, // D27 is P0.19 (QSPI CLK) + 17, // D28 is P0.17 (QSPI CS) + 20, // D29 is P0.20 (QSPI Data 0) + 21, // D30 is P0.21 (QSPI Data 1) + 22, // D31 is P0.22 (QSPI Data 2) + 23, // D32 is P0.23 (QSPI Data 3) + + // The remaining NFC pin + 9, // D33 is P0.09 (NFC1, exposed only via test point on bottom of board) + + // Thus, there are 34 defined pins + + // The remaining pins are not usable: + // + // + // The following pins were never listed as they were considered unusable + // 0, // P0.00 is XL1 (attached to 32.768kHz crystal) + // 1, // P0.01 is XL2 (attached to 32.768kHz crystal) + // 18, // P0.18 is RESET (attached to switch) + // 32, // P1.00 is SWO (attached to debug header) + // + // The remaining pins are not connected (per schematic) + // 33, // P1.01 is not connected per schematic + // 35, // P1.03 is not connected per schematic + // 36, // P1.04 is not connected per schematic + // 37, // P1.05 is not connected per schematic + // 38, // P1.06 is not connected per schematic + // 39, // P1.07 is not connected per schematic + // 43, // P1.11 is not connected per schematic + // 44, // P1.12 is not connected per schematic + // 45, // P1.13 is not connected per schematic + // 46, // P1.14 is not connected per schematic +}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); +} + diff --git a/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/variant.h b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/variant.h new file mode 100644 index 0000000..a5b7eb9 --- /dev/null +++ b/Packages_Patches/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/variant.h @@ -0,0 +1,159 @@ + /* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + 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 +*/ + +// Thanks to great work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip). +// See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) + +#ifndef _VARIANT_NINA_B302_UBLOX_ +#define _VARIANT_NINA_B302_UBLOX_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus +// (XX) = TABLE INDEX +// Number of pins defined in PinDescription array +#define PINS_COUNT (34) +#define NUM_DIGITAL_PINS (34) +#define NUM_ANALOG_INPUTS (6) // A6 is used for battery, A7 is analog reference +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (3) +#define PIN_LED2 (4) +#define PIN_NEOPIXEL (8) + +#define LED_BUILTIN PIN_LED1 +#define LED_CONN PIN_LED2 + +#define LED_RED PIN_LED1 +#define LED_BLUE PIN_LED2 + +#define LED_STATE_ON 1 // State when LED is litted + +/* + * Buttons + */ +#define PIN_BUTTON1 (7) + +/* + * Analog pins + */ +#define PIN_A0 (14) +#define PIN_A1 (15) +#define PIN_A2 (16) +#define PIN_A3 (17) +#define PIN_A4 (18) +#define PIN_A5 (19) +#define PIN_A6 (20) +#define PIN_A7 (21) + +#define D0 (0) +#define D1 (1) +#define D2 (2) +#define D3 (3) +#define D4 (4) +#define D5 (5) +#define D6 (6) +#define D7 (7) +#define D8 (8) +#define D9 (9) +#define D10 (10) +#define D11 (11) +#define D12 (12) +#define D13 (13) + +static const uint8_t A0 = PIN_A0 ; +static const uint8_t A1 = PIN_A1 ; +static const uint8_t A2 = PIN_A2 ; +static const uint8_t A3 = PIN_A3 ; +static const uint8_t A4 = PIN_A4 ; +static const uint8_t A5 = PIN_A5 ; +static const uint8_t A6 = PIN_A6 ; +static const uint8_t A7 = PIN_A7 ; +#define ADC_RESOLUTION 14 + +// Other pins +#define PIN_AREF PIN_A7 +#define PIN_VBAT PIN_A6 +#define PIN_NFC1 (33) +#define PIN_NFC2 (2) + +static const uint8_t AREF = PIN_AREF; + +/* + * Serial interfaces + */ +#define PIN_SERIAL1_RX (1) +#define PIN_SERIAL1_TX (0) + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (24) //24 original +#define PIN_SPI_MOSI (25) //25 original +#define PIN_SPI_SCK (26) //26 original + +static const uint8_t SS = (13); +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (22) +#define PIN_WIRE_SCL (23) + +// QSPI Pins +#define PIN_QSPI_SCK 27 +#define PIN_QSPI_CS 28 +#define PIN_QSPI_IO0 29 +#define PIN_QSPI_IO1 30 +#define PIN_QSPI_IO2 31 +#define PIN_QSPI_IO3 32 + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES GD25Q16C +#define EXTERNAL_FLASH_USE_QSPI + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif //_VARIANT_NINA_B302_UBLOX_ diff --git a/README.md b/README.md new file mode 100644 index 0000000..2350b2e --- /dev/null +++ b/README.md @@ -0,0 +1,899 @@ +# NRF52_TimerInterrupt Library + +[![arduino-library-badge](https://www.ardu-badge.com/badge/NRF52_TimerInterrupt.svg?)](https://www.ardu-badge.com/NRF52_TimerInterrupt) +[![GitHub release](https://img.shields.io/github/release/khoih-prog/NRF52_TimerInterrupt.svg)](https://github.com/khoih-prog/NRF52_TimerInterrupt/releases) +[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/NRF52_TimerInterrupt/blob/main/LICENSE) +[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) +[![GitHub issues](https://img.shields.io/github/issues/khoih-prog/NRF52_TimerInterrupt.svg)](http://github.com/khoih-prog/NRF52_TimerInterrupt/issues) + +--- +--- + +## Features + +This library enables you to use Interrupt from Hardware Timers on an NRF52-based board. + +### Why do we need this Hardware Timer Interrupt? + +Imagine you have a system with a **mission-critical** function, measuring water level and control the sump pump or doing something much more important. You normally use a software timer to poll, or even place the function in loop(). But what if another function is **blocking** the loop() or setup(). + +So your function **might not be executed, and the result would be disastrous.** + +You'd prefer to have your function called, no matter what happening with other functions (busy loop, bug, etc.). + +The correct choice is to use a Hardware Timer with **Interrupt** to call your function. + +These hardware timers, using interrupt, still work even if other functions are blocking. Moreover, they are much more **precise** (certainly depending on clock frequency accuracy) than other software timers using millis() or micros(). That's necessary if you need to measure some data requiring better accuracy. + +Functions using normal software timers, relying on loop() and calling millis(), won't work if the loop() or setup() is blocked by certain operation. For example, certain function is blocking while it's connecting to WiFi or some services. + +The catch is **your function is now part of an ISR (Interrupt Service Routine), and must be lean / mean, and follow certain rules.** More to read on: + +[**HOWTO Attach Interrupt**](https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/) + +--- + +#### Important Notes: + +1. Inside the attached function, **delay() won’t work and the value returned by millis() will not increment.** Serial data received while in the function may be lost. You should declare as **volatile any variables that you modify within the attached function.** + +2. Typically global variables are used to pass data between an ISR and the main program. To make sure variables shared between an ISR and the main program are updated correctly, declare them as volatile. + +--- +--- + +### Releases v1.0.0 + +1. Permit up to 16 super-long-time, super-accurate ISR-based timers to avoid being blocked +2. Using cpp code besides Impl.h code to use if Multiple-Definition linker error. + +#### Supported Boards + + - **AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B302_ublox, NINA_B112_ublox etc.** + +--- +--- + +## Prerequisite + + 1. [`Arduino IDE 1.8.13+` for Arduino](https://www.arduino.cc/en/Main/Software) + 2. [`Adafruit nRF52 v0.21.0+`](https://www.adafruit.com/) for nRF52 boards such as AdaFruit Feather nRF52840 Express, NINA_B302_ublox, etc. + 3. [`Blynk library 0.6.1+`](https://github.com/blynkkk/blynk-library) to use with certain example. + 4. To use with certain example, depending on which Ethernet card you're using: + - [`Ethernet library v2.0.0+`](https://www.arduino.cc/en/Reference/Ethernet) for W5100, W5200 and W5500. + - [`Ethernet2 library v1.0.4+`](https://github.com/khoih-prog/Ethernet2) for W5500 (Deprecated, use Arduino Ethernet library). + - [`Ethernet3 library v1.5.3+`](https://github.com/sstaub/Ethernet3) for W5500/WIZ550io/WIZ850io/USR-ES1 with Wiznet W5500 chip. + - [`EthernetLarge library v2.0.0+`](https://github.com/OPEnSLab-OSU/EthernetLarge) for W5100, W5200 and W5500. ***Ready*** from v1.0.1. + - [`UIPEthernet library v2.0.9+`](https://github.com/UIPEthernet/UIPEthernet) for ENC28J60. + 5. [`WiFiNINA_Generic library v1.7.1+`](https://github.com/khoih-prog/WiFiNINA_Generic) to use WiFiNINA modules/shields. To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/WiFiNINA_Generic.svg?)](https://www.ardu-badge.com/WiFiNINA_Generic) if using WiFiNINA for boards such as nRF52, etc. + 6. [`Blynk_WiFiNINA_WM library 1.0.4+`](hhttps://github.com/khoih-prog/Blynk_WiFiNINA_WM) to use with Blynk-WiFiNINA-related example. + +--- +--- + +## Installation + +### Use Arduino Library Manager + +The best and easiest way is to use `Arduino Library Manager`. Search for [**NRF52_TimerInterrupt**](https://github.com/khoih-prog/NRF52_TimerInterrupt), then select / install the latest version. +You can also use this link [![arduino-library-badge](https://www.ardu-badge.com/badge/NRF52_TimerInterrupt.svg?)](https://www.ardu-badge.com/NRF52_TimerInterrupt) for more detailed instructions. + +### Manual Install + +Another way to install is to: + +1. Navigate to [**NRF52_TimerInterrupt**](https://github.com/khoih-prog/NRF52_TimerInterrupt) page. +2. Download the latest release `NRF52_TimerInterrupt-main.zip`. +3. Extract the zip file to `NRF52_TimerInterrupt-main` directory +4. Copy whole `NRF52_TimerInterrupt-main` folder to Arduino libraries' directory such as `~/Arduino/libraries/`. + +### VS Code & PlatformIO + +1. Install [VS Code](https://code.visualstudio.com/) +2. Install [PlatformIO](https://platformio.org/platformio-ide) +3. Install [**NRF52_TimerInterrupt** library](https://platformio.org/lib/show/11399/NRF52_TimerInterrupt) by using [Library Manager](https://platformio.org/lib/show/11399/NRF52_TimerInterrupt/installation). Search for **NRF52_TimerInterrupt** in [Platform.io Author's Libraries](https://platformio.org/lib/search?query=author:%22Khoi%20Hoang%22) +4. Use included [platformio.ini](platformio/platformio.ini) file from examples to ensure that all dependent libraries will installed automatically. Please visit documentation for the other options and examples at [Project Configuration File](https://docs.platformio.org/page/projectconf.html) + +--- +--- + +### Packages' Patches + + 1. **To be able to compile, run and automatically detect and display BOARD_NAME on nRF52840/nRF52832 boards**, you have to copy the whole [nRF52 0.21.0](Packages_Patches/adafruit/hardware/nrf52/0.21.0) directory into Adafruit nRF52 directory (~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0). + +Supposing the Adafruit nRF52 version is 0.21.0. These files must be copied into the directory: +- `~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/platform.txt` +- `~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/boards.txt` +- `~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/variant.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/variant.cpp` +- `~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/variant.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/variant.cpp` +- **`~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/cores/nRF5/Udp.h`** + +Whenever a new version is installed, remember to copy these files into the new version directory. For example, new version is x.yy.z +These files must be copied into the directory: + +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/platform.txt` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/boards.txt` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/variants/NINA_B302_ublox/variant.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/variants/NINA_B302_ublox/variant.cpp` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/variants/NINA_B112_ublox/variant.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/variants/NINA_B112_ublox/variant.cpp` +- **`~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/cores/nRF5/Udp.h`** + +--- +--- + +### Libraries' Patches + +1. If your application requires 2K+ HTML page, the current [`Ethernet library`](https://www.arduino.cc/en/Reference/Ethernet) must be modified if you are using W5200/W5500 Ethernet shields. W5100 is not supported for 2K+ buffer. If you use boards requiring different CS/SS pin for W5x00 Ethernet shield, for example ESP32, ESP8266, nRF52, etc., you also have to modify the following libraries to be able to specify the CS/SS pin correctly. + +2. To fix [`Ethernet library`](https://www.arduino.cc/en/Reference/Ethernet), just copy these following files into the [`Ethernet library`](https://www.arduino.cc/en/Reference/Ethernet) directory to overwrite the old files: +- [Ethernet.h](LibraryPatches/Ethernet/src/Ethernet.h) +- [Ethernet.cpp](LibraryPatches/Ethernet/src/Ethernet.cpp) +- [EthernetServer.cpp](LibraryPatches/Ethernet/src/EthernetServer.cpp) +- [w5100.h](LibraryPatches/Ethernet/src/utility/w5100.h) +- [w5100.cpp](LibraryPatches/Ethernet/src/utility/w5100.cpp) + +3. To fix [`EthernetLarge library`](https://github.com/OPEnSLab-OSU/EthernetLarge), just copy these following files into the [`EthernetLarge library`](https://github.com/OPEnSLab-OSU/EthernetLarge) directory to overwrite the old files: +- [EthernetLarge.h](LibraryPatches/EthernetLarge/src/EthernetLarge.h) +- [EthernetLarge.cpp](LibraryPatches/EthernetLarge/src/EthernetLarge.cpp) +- [EthernetServer.cpp](LibraryPatches/EthernetLarge/src/EthernetServer.cpp) +- [w5100.h](LibraryPatches/EthernetLarge/src/utility/w5100.h) +- [w5100.cpp](LibraryPatches/EthernetLarge/src/utility/w5100.cpp) + +4. To fix [`Ethernet2 library`](https://github.com/khoih-prog/Ethernet2), just copy these following files into the [`Ethernet2 library`](https://github.com/khoih-prog/Ethernet2) directory to overwrite the old files: + +- [Ethernet2.h](LibraryPatches/Ethernet2/src/Ethernet2.h) +- [Ethernet2.cpp](LibraryPatches/Ethernet2/src/Ethernet2.cpp) + +To add UDP Multicast support, necessary for this [**UPnP_Generic library**](https://github.com/khoih-prog/UPnP_Generic): + +- [EthernetUdp2.h](LibraryPatches/Ethernet2/src/EthernetUdp2.h) +- [EthernetUdp2.cpp](LibraryPatches/Ethernet2/src/EthernetUdp2.cpp) + +5. To fix [`Ethernet3 library`](https://github.com/sstaub/Ethernet3), just copy these following files into the [`Ethernet3 library`](https://github.com/sstaub/Ethernet3) directory to overwrite the old files: +- [Ethernet3.h](LibraryPatches/Ethernet3/src/Ethernet3.h) +- [Ethernet3.cpp](LibraryPatches/Ethernet3/src/Ethernet3.cpp) + +6. **To be able to compile and run on nRF52 boards with ENC28J60 using UIPEthernet library**, you have to copy these following files into the UIPEthernet `utility` directory to overwrite the old files: + +- For [UIPEthernet v2.0.8](https://github.com/UIPEthernet/UIPEthernet) + + - [UIPEthernet.h](LibraryPatches/UIPEthernet/UIPEthernet.h) + - [UIPEthernet.cpp](LibraryPatches/UIPEthernet/UIPEthernet.cpp) + - [Enc28J60Network.h](LibraryPatches/UIPEthernet/utility/Enc28J60Network.h) + - [Enc28J60Network.cpp](LibraryPatches/UIPEthernet/utility/Enc28J60Network.cpp) + +- For [UIPEthernet v2.0.9](https://github.com/UIPEthernet/UIPEthernet) + + - [UIPEthernet.h](LibraryPatches/UIPEthernet-2.0.9/UIPEthernet.h) + - [UIPEthernet.cpp](LibraryPatches/UIPEthernet-2.0.9/UIPEthernet.cpp) + - [Enc28J60Network.h](LibraryPatches/UIPEthernet-2.0.9/utility/Enc28J60Network.h) + - [Enc28J60Network.cpp](LibraryPatches/UIPEthernet-2.0.9/utility/Enc28J60Network.cpp) + +7. Check if you need to install the UIPthernet patch [new NRF52 core F3/F4 compatibility](https://github.com/UIPEthernet/UIPEthernet/commit/c6d6519a260166b722b9cee5dd1f0fb2682e6782) to avoid errors `#include HardwareSPI.h` on some NRF52 boards (Nucleo-32 F303K8, etc.) + +--- +--- + +### HOWTO Fix `Multiple Definitions` Linker Error + +The current library implementation, using **xyz-Impl.h instead of standard xyz.cpp**, possibly creates certain `Multiple Definitions` Linker error in certain use cases. Although it's simple to just modify several lines of code, either in the library or in the application, the library is adding 2 more source directories + +1. **scr_h** for new h-only files +2. **src_cpp** for standard h/cpp files + +besides the standard **src** directory. + +To use the **old standard cpp** way, locate this library' directory, then just + +1. **Delete the all the files in src directory.** +2. **Copy all the files in src_cpp directory into src.** +3. Close then reopen the application code in Arduino IDE, etc. to recompile from scratch. + +To re-use the **new h-only** way, just + +1. **Delete the all the files in src directory.** +2. **Copy the files in src_h directory into src.** +3. Close then reopen the application code in Arduino IDE, etc. to recompile from scratch. + +--- +--- + + +## New from v1.0.0 + +Now with these new `16 ISR-based timers` (while consuming only **1 hardware timer**), the maximum interval is practically unlimited (limited only by unsigned long miliseconds). The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers Therefore, their executions are not blocked by bad-behaving functions / tasks. +This important feature is absolutely necessary for mission-critical tasks. + +The [**ISR_Timer_Complex_Ethernet**](examples/ISR_Timer_Complex_Ethernet) and [**ISR_Timer_Complex_WiFiNINA**](examples/ISR_Timer_Complex_WiFiNINA) examples will demonstrate the nearly perfect accuracy compared to software timers by printing the actual elapsed millisecs of each type of timers. +Being ISR-based timers, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet and Blynk services. You can also have many `(up to 16)` timers to use. +This non-being-blocked important feature is absolutely necessary for mission-critical tasks. +You'll see blynkTimer Software is blocked while system is connecting to WiFi / Internet / Blynk, as well as by blocking task +in loop(), using delay() function as an example. The elapsed time then is very unaccurate + +--- + +## Supported Boards + +- NRF52832 and nRF52840 + +--- + +## Usage + +Before using any Timer, you have to make sure the Timer has not been used by any other purpose. + +### 1. Using only Hardware Timer directly + +#### 1.1 Init Hardware Timer + +``` +// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4) +// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1 + +// Init NRF52 timer NRF_TIMER1 +NRF52Timer ITimer(NRF_TIMER_1); +``` + +#### 1.2 Set Hardware Timer Interval and attach Timer Interrupt Handler function + +``` +void TimerHandler(void) +{ + // Doing something here inside ISR +} + +#define TIMER_INTERVAL_MS 1000 // 1s = 1000ms +void setup() +{ + .... + + // Interval in microsecs + if (ITimer.attachInterruptInterval(TIMER_INTERVAL_MS * 1000, TimerHandler0)) + Serial.println("Starting ITimer OK, millis() = " + String(millis())); + else + Serial.println("Can't set ITimer. Select another freq. or timer"); +} +``` + +### 2. Using 16 ISR_based Timers from 1 Hardware Timers + + +#### 2.1 Init Hardware Timer and ISR-based Timer + +``` +/// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4) +// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1 + +// Init NRF52 timer NRF_TIMER2 +NRF52Timer ITimer(NRF_TIMER_2); + +// Init NRF52_ISR_Timer +// Each NRF52_ISR_Timer can service 16 different ISR-based timers +NRF52_ISR_Timer ISR_Timer; +``` + +#### 2.2 Set Hardware Timer Interval and attach Timer Interrupt Handler functions + +``` +void TimerHandler(void) +{ + ISR_Timer.run(); +} + +#define HW_TIMER_INTERVAL_MS 50L + +#define TIMER_INTERVAL_2S 2000L +#define TIMER_INTERVAL_5S 5000L +#define TIMER_INTERVAL_11S 11000L +#define TIMER_INTERVAL_101S 101000L + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething2s() +{ + // Doing something here inside ISR +} + +void doingSomething5s() +{ + // Doing something here inside ISR +} + +void doingSomething11s() +{ + // Doing something here inside ISR +} + +void doingSomething101s() +{ + // Doing something here inside ISR +} + +void setup() +{ + .... + + // Interval in microsecs + if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_MS * 1000, TimerHandler)) + { + lastMillis = millis(); + Serial.println("Starting ITimer OK, millis() = " + String(lastMillis)); + } + else + Serial.println("Can't set ITimer correctly. Select another freq. or interval"); + + // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary + // You can use up to 16 timer for each ISR_Timer + ISR_Timer.setInterval(TIMER_INTERVAL_2S, doingSomething2s); + ISR_Timer.setInterval(TIMER_INTERVAL_5S, doingSomething5s); + ISR_Timer.setInterval(TIMER_INTERVAL_11S, doingSomething11s); + ISR_Timer.setInterval(TIMER_INTERVAL_101S, doingSomething101s); +} +``` + +--- +--- + +### Examples: + + 1. [Argument_None](examples/Argument_None) + 2. [ISR_RPM_Measure](examples/ISR_RPM_Measure) + 3. [ISR_Timer_Complex_Ethernet](examples/ISR_Timer_Complex_Ethernet) + 4. [ISR_Timer_Complex_WiFiNINA](examples/ISR_Timer_Complex_WiFiNINA) + 5. [RPM_Measure](examples/RPM_Measure) + 6. [SwitchDebounce](examples/SwitchDebounce) + 7. [TimerInterruptTest](examples/TimerInterruptTest) + 8. [TimerInterruptLEDDemo](examples/TimerInterruptLEDDemo) + + +--- +--- + +### Example [ISR_Timer_Complex_Ethernet](examples/ISR_Timer_Complex_Ethernet) + +``` +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +#define BLYNK_PRINT Serial + +//#define BLYNK_DEBUG +#ifdef BLYNK_DEBUG + #undef BLYNK_DEBUG +#endif + +/* Comment this out to disable prints and save space */ +#define BLYNK_PRINT Serial + +// If don't use USE_UIP_ETHERNET => use W5x00 with Ethernet library +#define USE_UIP_ETHERNET false + +#if (USE_UIP_ETHERNET) + #define ETHERNET_NAME "ENC28J60 Ethernet Shield" +#else + #define ETHERNET_NAME "W5x00 Ethernet Shield" +#endif + +#define BLYNK_NO_YIELD + +#if USE_UIP_ETHERNET + #include +#else + #include +#endif + +#define USE_LOCAL_SERVER true + +#if USE_LOCAL_SERVER + char auth[] = "******"; + char server[] = "account.duckdns.org"; + //char server[] = "192.168.2.112"; + +#else + char auth[] = "******"; + char server[] = "blynk-cloud.com"; +#endif + + #define BLYNK_HARDWARE_PORT 8080 + +#if !(USE_UIP_ETHERNET) + #define W5100_CS 10 + #define SDCARD_CS 4 +#endif + +// These define's must be placed at the beginning before #include "NRF52TimerInterrupt.h" +#define NRF52_TIMER_INTERRUPT_DEBUG 1 + +#include "NRF52TimerInterrupt.h" +#include "NRF52_ISR_Timer.h" + +#define HW_TIMER_INTERVAL_MS 1 + +volatile uint32_t lastMillis = 0; + +// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4) +// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1 + +// Init NRF52 timer NRF_TIMER1 +NRF52Timer ITimer(NRF_TIMER_2); + +// Init NRF52_ISR_Timer +// Each NRF52_ISR_Timer can service 16 different ISR-based timers +NRF52_ISR_Timer ISR_Timer; + +// Ibit Blynk Timer +BlynkTimer blynkTimer; + +#ifndef LED_BUILTIN + #define LED_BUILTIN PB0 // Pin 33/PB0 control on-board LED_GREEN on F767ZI +#endif + +#define LED_TOGGLE_INTERVAL_MS 5000L + +#define TIMER_INTERVAL_2S 2000L +#define TIMER_INTERVAL_5S 5000L +#define TIMER_INTERVAL_11S 11000L +#define TIMER_INTERVAL_21S 21000L + +void TimerHandler(void) +{ + static bool toggle = false; + static bool started = false; + static int timeRun = 0; + + ISR_Timer.run(); + + // Toggle LED every LED_TOGGLE_INTERVAL_MS = 5000ms = 5s + if (++timeRun == (LED_TOGGLE_INTERVAL_MS / HW_TIMER_INTERVAL_MS) ) + { + timeRun = 0; + + if (!started) + { + started = true; + pinMode(LED_BUILTIN, OUTPUT); + } + + //timer interrupt toggles pin LED_BUILTIN + digitalWrite(LED_BUILTIN, toggle); + toggle = !toggle; + } +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething2s() +{ + static unsigned long previousMillis = lastMillis; + unsigned long deltaMillis = millis() - previousMillis; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + if (previousMillis > TIMER_INTERVAL_2S) + { + Serial.print("2s: Delta ms = "); + Serial.println(deltaMillis); + } +#endif + + previousMillis = millis(); +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething5s() +{ + static unsigned long previousMillis = lastMillis; + unsigned long deltaMillis = millis() - previousMillis; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + if (previousMillis > TIMER_INTERVAL_5S) + { + Serial.print("5s: Delta ms = "); + Serial.println(deltaMillis); + } +#endif + + previousMillis = millis(); +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething11s() +{ + static unsigned long previousMillis = lastMillis; + unsigned long deltaMillis = millis() - previousMillis; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + if (previousMillis > TIMER_INTERVAL_11S) + { + Serial.print("11s: Delta ms = "); + Serial.println(deltaMillis); + } +#endif + + previousMillis = millis(); +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething21s() +{ + static unsigned long previousMillis = lastMillis; + unsigned long deltaMillis = millis() - previousMillis; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + if (previousMillis > TIMER_INTERVAL_21S) + { + Serial.print("21s: Delta ms = "); + Serial.println(deltaMillis); + } +#endif + + previousMillis = millis(); +} + +#define BLYNK_TIMER_MS 2000L + +// Here is software Timer, you can do somewhat fancy stuffs without many issues. +// But always avoid +// 1. Long delay() it just doing nothing and pain-without-gain wasting CPU power.Plan and design your code / strategy ahead +// 2. Very long "do", "while", "for" loops without predetermined exit time. +void blynkDoingSomething2s() +{ + static unsigned long previousMillis = lastMillis; + Serial.println("blynkDoingSomething2s: Delta programmed ms = " + String(BLYNK_TIMER_MS) + ", actual = " + String(millis() - previousMillis)); + previousMillis = millis(); +} + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + Serial.println("\nStarting ISR_Timer_Complex_Ethernet on " + String(BOARD_NAME)); + Serial.println("Version : " + String(NRF52_TIMER_INTERRUPT_VERSION)); + + // You need this timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary. + blynkTimer.setInterval(BLYNK_TIMER_MS, blynkDoingSomething2s); + + // Interval in microsecs + if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_MS * 1000, TimerHandler)) + { + lastMillis = millis(); + Serial.println("Starting ITimer OK, millis() = " + String(lastMillis)); + } + else + Serial.println("Can't set ITimer correctly. Select another freq. or interval"); + + // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary + // You can use up to 16 timer for each ISR_Timer + ISR_Timer.setInterval(TIMER_INTERVAL_2S, doingSomething2s); + ISR_Timer.setInterval(TIMER_INTERVAL_5S, doingSomething5s); + ISR_Timer.setInterval(TIMER_INTERVAL_11S, doingSomething11s); + ISR_Timer.setInterval(TIMER_INTERVAL_21S, doingSomething21s); + +#if !(USE_BUILTIN_ETHERNET || USE_UIP_ETHERNET) + pinMode(SDCARD_CS, OUTPUT); + digitalWrite(SDCARD_CS, HIGH); // Deselect the SD card +#endif + +#if USE_LOCAL_SERVER + Blynk.begin(auth, server, BLYNK_HARDWARE_PORT); +#else + Blynk.begin(auth); + // You can also specify server: + //Blynk.begin(auth, server, BLYNK_HARDWARE_PORT); +#endif + + if (Blynk.connected()) + { + Serial.print(F("IP = ")); + Serial.println(Ethernet.localIP()); + } +} + +#define BLOCKING_TIME_MS 3000L + +void loop() +{ + Blynk.run(); + + // This unadvised blocking task is used to demonstrate the blocking effects onto the execution and accuracy to Software timer + // You see the time elapse of ISR_Timer still accurate, whereas very unaccurate for Software Timer + // The time elapse for 2000ms software timer now becomes 3000ms (BLOCKING_TIME_MS) + // While that of ISR_Timer is still prefect. + delay(BLOCKING_TIME_MS); + + // You need this Software timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary + // You don't need to and never call ISR_Timer.run() here in the loop(). It's already handled by ISR timer. + blynkTimer.run(); +} +``` +--- +--- + +### Debug Terminal Output Samples + +1. The following is the sample terminal output when running example [ISR_Timer_Complex_Ethernet](examples/ISR_Timer_Complex_Ethernet) on **Adafruit NRF52840_FEATHER EXPRESS using W5500 Ethernet* to demonstrate the accuracy of ISR Hardware Timer, **especially when system is very busy**. The ISR timer is **programmed for 2s, is activated exactly after 2.000s !!!** + +While software timer, **programmed for 2s, is activated after 4.867s !!!**. Then in loop(), it's also activated **every 3s**. + +``` +Starting ISR_Timer_Complex_Ethernet on NRF52840_FEATHER +Version : 1.0.0 +NRF52TimerInterrupt: F_CPU (MHz) = 64, Timer = NRF_TIMER2 +NRF52TimerInterrupt: _fre = 1000000.00, _count = 50000 +Starting ITimer OK, millis() = 1419 +[1419] Getting IP... +[1419] MAC: FE-BE-97-DA-C3-EA +_pinCS = 0 +W5100 init, using SS_PIN_DEFAULT = 10, new ss_pin = 10, W5100Class::ss_pin = 10 +W5100::init: W5500, SSIZE =4096 +[3104] IP:192.168.2.129 +[3104] + ___ __ __ + / _ )/ /_ _____ / /__ + / _ / / // / _ \/ '_/ + /____/_/\_, /_//_/_/\_\ + /___/ v0.6.1 on ARDUINO_NRF52_ADAFRUIT + +[3106] BlynkArduinoClient.connect: Connecting to account.duckdns.org:8080 +[3218] Ready (ping: 8ms). +IP = 192.168.2.129 +2s: Delta ms = 2000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 4867 +2s: Delta ms = 2000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +2s: Delta ms = 2000 +5s: Delta ms = 5000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +5s: Delta ms = 5000 +2s: Delta ms = 2000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +5s: Delta ms = 5000 +2s: Delta ms = 2000 +11s: Delta ms = 11000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +5s: Delta ms = 5000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +2s: Delta ms = 2000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +5s: Delta ms = 5000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +11s: Delta ms = 11000 +2s: Delta ms = 2000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +5s: Delta ms = 5000 +2s: Delta ms = 2000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +2s: Delta ms = 2000 +5s: Delta ms = 5000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +21s: Delta ms = 21000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +11s: Delta ms = 11000 +5s: Delta ms = 5000 +2s: Delta ms = 2000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +5s: Delta ms = 5000 +2s: Delta ms = 2000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +2s: Delta ms = 2000 +5s: Delta ms = 5000 +11s: Delta ms = 11000 +blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000 +``` + +--- + +2. The following is the sample terminal output when running example [**TimerInterruptTest**](examples/TimerInterruptTest) on **Adafruit NRF52840_ITSYBITSY** to demonstrate the accuracy and how to start/stop Hardware Timers. + +``` +Starting TimerInterruptTest on NRF52840_ITSYBITSY +Version : 1.0.0 +NRF52TimerInterrupt: F_CPU (MHz) = 64, Timer = NRF_TIMER1 +NRF52TimerInterrupt: _fre = 1000000.00, _count = 1000000 +Starting ITimer1 OK, millis() = 834 +NRF52TimerInterrupt: F_CPU (MHz) = 64, Timer = NRF_TIMER2 +NRF52TimerInterrupt: _fre = 1000000.00, _count = 3000000 +Starting ITimer1 OK, millis() = 835 +ITimer0: millis() = 1834, delta = 1000 +ITimer0: millis() = 2834, delta = 1000 +ITimer0: millis() = 3834, delta = 1000 +ITimer1: millis() = 3835, delta = 3000 +ITimer0: millis() = 4834, delta = 1000 +Stop ITimer0, millis() = 5001 +ITimer1: millis() = 6835, delta = 3000 +ITimer1: millis() = 9835, delta = 3000 +Start ITimer0, millis() = 10002 +ITimer0: millis() = 11002, delta = 1000 +ITimer0: millis() = 12002, delta = 1000 +ITimer1: millis() = 12835, delta = 3000 +ITimer0: millis() = 13002, delta = 1000 +ITimer0: millis() = 14002, delta = 1000 +Stop ITimer1, millis() = 15001 +ITimer0: millis() = 15002, delta = 1000 +Stop ITimer0, millis() = 15003 +Start ITimer0, millis() = 20004 +ITimer0: millis() = 21004, delta = 1000 +ITimer0: millis() = 22004, delta = 1000 +ITimer0: millis() = 23004, delta = 1000 +ITimer0: millis() = 24004, delta = 1000 +ITimer0: millis() = 25004, delta = 1000 +Stop ITimer0, millis() = 25005 +Start ITimer1, millis() = 30002 +Start ITimer0, millis() = 30006 +ITimer0: millis() = 31006, delta = 1000 +ITimer0: millis() = 32006, delta = 1000 +ITimer1: millis() = 33002, delta = 3000 +ITimer0: millis() = 33006, delta = 1000 +ITimer0: millis() = 34006, delta = 1000 +ITimer0: millis() = 35006, delta = 1000 +Stop ITimer0, millis() = 35007 +ITimer1: millis() = 36002, delta = 3000 +ITimer1: millis() = 39002, delta = 3000 +Start ITimer0, millis() = 40008 +ITimer0: millis() = 41008, delta = 1000 +ITimer1: millis() = 42002, delta = 3000 +ITimer0: millis() = 42008, delta = 1000 +ITimer0: millis() = 43008, delta = 1000 +ITimer0: millis() = 44008, delta = 1000 +ITimer1: millis() = 45002, delta = 3000 +Stop ITimer1, millis() = 45003 +ITimer0: millis() = 45008, delta = 1000 +Stop ITimer0, millis() = 45009 +Start ITimer0, millis() = 50010 +ITimer0: millis() = 51010, delta = 1000 +ITimer0: millis() = 52010, delta = 1000 +ITimer0: millis() = 53010, delta = 1000 +ITimer0: millis() = 54010, delta = 1000 +ITimer0: millis() = 55010, delta = 1000 +``` + +--- + +3. The following is the sample terminal output when running example [**Argument_None**](examples/Argument_None) on **Adafruit NRF52840_ITSYBITSY** to demonstrate the accuracy of Hardware Timers. + +``` +Starting Argument_None on NRF52840_ITSYBITSY +Version : 1.0.0 +NRF52TimerInterrupt: F_CPU (MHz) = 64, Timer = NRF_TIMER1 +NRF52TimerInterrupt: _fre = 1000000.00, _count = 1000000 +Starting ITimer0 OK, millis() = 948 +NRF52TimerInterrupt: F_CPU (MHz) = 64, Timer = NRF_TIMER4 +NRF52TimerInterrupt: _fre = 1000000.00, _count = 5000000 +Starting ITimer1 OK, millis() = 949 +ITimer0: millis() = 1948, delta = 1000 +ITimer0: millis() = 2948, delta = 1000 +ITimer0: millis() = 3948, delta = 1000 +ITimer0: millis() = 4948, delta = 1000 +ITimer0: millis() = 5948, delta = 1000 +ITimer1: millis() = 5949, delta = 5000 +ITimer0: millis() = 6948, delta = 1000 +ITimer0: millis() = 7948, delta = 1000 +ITimer0: millis() = 8949, delta = 1001 +ITimer0: millis() = 9949, delta = 1000 +ITimer0: millis() = 10949, delta = 1000 +ITimer1: millis() = 10949, delta = 5000 +ITimer0: millis() = 11949, delta = 1000 +ITimer0: millis() = 12949, delta = 1000 +ITimer0: millis() = 13949, delta = 1000 +ITimer0: millis() = 14949, delta = 1000 +ITimer1: millis() = 15949, delta = 5000 +ITimer0: millis() = 15949, delta = 1000 +ITimer0: millis() = 16949, delta = 1000 +ITimer0: millis() = 17949, delta = 1000 +ITimer0: millis() = 18949, delta = 1000 +ITimer0: millis() = 19949, delta = 1000 +ITimer1: millis() = 20949, delta = 5000 +ITimer0: millis() = 20949, delta = 1000 +ITimer0: millis() = 21950, delta = 1001 +ITimer0: millis() = 22950, delta = 1000 +ITimer0: millis() = 23950, delta = 1000 +ITimer0: millis() = 24950, delta = 1000 +ITimer1: millis() = 25949, delta = 5000 +ITimer0: millis() = 25950, delta = 1000 +ITimer0: millis() = 26950, delta = 1000 +ITimer0: millis() = 27950, delta = 1000 +ITimer0: millis() = 28950, delta = 1000 +ITimer0: millis() = 29950, delta = 1000 +ITimer1: millis() = 30949, delta = 5000 +ITimer0: millis() = 30950, delta = 1000 +ITimer0: millis() = 31950, delta = 1000 +ITimer0: millis() = 32950, delta = 1000 + +``` +--- +--- + +### Releases v1.0.0 + +1. Permit up to 16 super-long-time, super-accurate ISR-based timers to avoid being blocked +2. Using cpp code besides Impl.h code to use if Multiple-Definition linker error. + +#### Supported Boards + + - **AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B302_ublox, NINA_B112_ublox etc.** + +--- +--- + +### Issues ### + +Submit issues to: [NRF52_TimerInterrupt issues](https://github.com/khoih-prog/NRF52_TimerInterrupt/issues) + +--- + +## TO DO + +1. Search for bug and improvement. + + +## DONE + +For current version v1.0.0 + +1. Basic hardware timers for NRF52832 and NRF52840. +2. More hardware-initiated software-enabled timers +3. Longer time interval + +--- +--- + +### Contributions and Thanks + +Many thanks for everyone for bug reporting, new feature suggesting, testing and contributing to the development of this library. + + +--- + +## Contributing + +If you want to contribute to this project: +- Report bugs and errors +- Ask for enhancements +- Create issues and pull requests +- Tell other people about this library + +--- + +### License + +- The library is licensed under [MIT](https://github.com/khoih-prog/NRF52_TimerInterrupt/blob/main/LICENSE) + +--- + +## Copyright + +Copyright 2020- Khoi Hoang + + diff --git a/examples/Argument_None/Argument_None.ino b/examples/Argument_None/Argument_None.ino new file mode 100644 index 0000000..76745a2 --- /dev/null +++ b/examples/Argument_None/Argument_None.ino @@ -0,0 +1,172 @@ +/**************************************************************************************************************************** + Argument_None.ino + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ + +/* + Notes: + Special design is necessary to share data between interrupt code and the rest of your program. + Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume + variable can not spontaneously change. Because your function may change variables while your program is using them, + the compiler needs this hint. But volatile alone is often not enough. + When accessing shared variables, usually interrupts must be disabled. Even with volatile, + if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly. + If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled + or the entire sequence of your code which accesses the data. +*/ + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +// These define's must be placed at the beginning before #include "NRF52TimerInterrupt.h" +// Don't define NRF52_TIMER_INTERRUPT_DEBUG > 2. Only for special ISR debugging only. Can hang the system. +#define NRF52_TIMER_INTERRUPT_DEBUG 1 + +#include "NRF52TimerInterrupt.h" + +//#ifndef LED_BUILTIN +// #define LED_BUILTIN 3 +//#endif + +#ifndef LED_BLUE_PIN + #define LED_BLUE_PIN 7 +#endif + +#ifndef LED_RED + #define LED_RED 8 +#endif + +#define TIMER0_INTERVAL_MS 1000 //1000 +#define TIMER1_INTERVAL_MS 5000 + +volatile uint32_t preMillisTimer0 = 0; +volatile uint32_t preMillisTimer1 = 0; + +// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4) +// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1 + +// Init NRF52 timer NRF_TIMER1 +NRF52Timer ITimer0(NRF_TIMER_1); + +// Init NRF52 timer NRF_TIMER2 +NRF52Timer ITimer1(NRF_TIMER_2); + +void TimerHandler0(void) +{ + static bool toggle0 = false; + static bool started = false; + static uint32_t curMillis = 0; + + if (!started) + { + started = true; + pinMode(LED_BUILTIN, OUTPUT); + } + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + curMillis = millis(); + + if (curMillis > TIMER0_INTERVAL_MS) + { + Serial.println("ITimer0: millis() = " + String(curMillis) + ", delta = " + String(curMillis - preMillisTimer0)); + } + + preMillisTimer0 = curMillis; +#endif + + //timer interrupt toggles pin LED_BUILTIN + digitalWrite(LED_BUILTIN, toggle0); + toggle0 = !toggle0; +} + +void TimerHandler1(void) +{ + static bool toggle1 = false; + static bool started = false; + static uint32_t curMillis = 0; + + if (!started) + { + started = true; + pinMode(LED_BLUE_PIN, OUTPUT); + } + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + curMillis = millis(); + + if (curMillis > TIMER1_INTERVAL_MS) + { + Serial.println("ITimer1: millis() = " + String(curMillis) + ", delta = " + String(curMillis - preMillisTimer1)); + } + + preMillisTimer1 = curMillis; +#endif + + //timer interrupt toggles outputPin + digitalWrite(LED_BLUE_PIN, toggle1); + toggle1 = !toggle1; +} + +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + pinMode(LED_BLUE_PIN, OUTPUT); + + Serial.begin(115200); + while (!Serial); + + delay(100); + + Serial.println("\nStarting Argument_None on " + String(BOARD_NAME)); + Serial.println("Version : " + String(NRF52_TIMER_INTERRUPT_VERSION)); + + // Interval in microsecs + if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0)) + { + preMillisTimer0 = millis(); + Serial.println("Starting ITimer0 OK, millis() = " + String(preMillisTimer0)); + } + else + Serial.println("Can't set ITimer0. Select another freq. or timer"); + + // Interval in microsecs + if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1)) + { + preMillisTimer1 = millis(); + Serial.println("Starting ITimer1 OK, millis() = " + String(preMillisTimer1)); + } + else + Serial.println("Can't set ITimer1. Select another freq. or timer"); +} + +void loop() +{ + +} diff --git a/examples/ISR_RPM_Measure/ISR_RPM_Measure.ino b/examples/ISR_RPM_Measure/ISR_RPM_Measure.ino new file mode 100644 index 0000000..a00f61c --- /dev/null +++ b/examples/ISR_RPM_Measure/ISR_RPM_Measure.ino @@ -0,0 +1,169 @@ +/**************************************************************************************************************************** + ISR_RPM_Measure.ino + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ +/* + Notes: + Special design is necessary to share data between interrupt code and the rest of your program. + Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume + variable can not spontaneously change. Because your function may change variables while your program is using them, + the compiler needs this hint. But volatile alone is often not enough. + When accessing shared variables, usually interrupts must be disabled. Even with volatile, + if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly. + If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled + or the entire sequence of your code which accesses the data. + + RPM Measuring uses high frequency hardware timer 1Hz == 1ms) to measure the time from of one rotation, in ms + then convert to RPM. One rotation is detected by reading the state of a magnetic REED SW or IR LED Sensor + Asssuming LOW is active. + For example: Max speed is 600RPM => 10 RPS => minimum 100ms a rotation. We'll use 80ms for debouncing + If the time between active state is less than 8ms => consider noise. + RPM = 60000 / (rotation time in ms) + + We use interrupt to detect whenever the SW is active, set a flag + then use timer to count the time between active state +*/ + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || defined(NRF52840_CLUE) || \ + defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +// These define's must be placed at the beginning before #include "NRF52TimerInterrupt.h" +// Don't define NRF52_TIMER_INTERRUPT_DEBUG > 2. Only for special ISR debugging only. Can hang the system. +#define NRF52_TIMER_INTERRUPT_DEBUG 1 + +#include "NRF52TimerInterrupt.h" + +//#ifndef LED_BUILTIN +// #define LED_BUILTIN 3 +//#endif + +#ifndef LED_BLUE_PIN + #define LED_BLUE_PIN 9 +#endif + +#ifndef LED_RED + #define LED_RED 8 +#endif + +unsigned int interruptPin = 7; + +#define TIMER1_INTERVAL_MS 1 +#define DEBOUNCING_INTERVAL_MS 80 + +#define LOCAL_DEBUG 1 + +// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4) +// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1 + +// Init NRF52 timer NRF_TIMER1 +NRF52Timer ITimer1(NRF_TIMER_1); + +// Init NRF52 timer NRF_TIMER2 +//NRF52Timer ITimer1(NRF_TIMER_4); + +volatile unsigned long rotationTime = 0; +float RPM = 0.00; +float avgRPM = 0.00; + +volatile int debounceCounter; + +volatile bool activeState = false; + +void detectRotation(void) +{ + activeState = true; +} + +void TimerHandler1() +{ + static bool started = false; + + if ( activeState ) + { + // Reset to prepare for next round of interrupt + activeState = false; + + if (debounceCounter >= DEBOUNCING_INTERVAL_MS / TIMER1_INTERVAL_MS ) + { + + //min time between pulses has passed + RPM = (float) ( 60000.0f / ( rotationTime * TIMER1_INTERVAL_MS ) ); + + avgRPM = ( 2 * avgRPM + RPM) / 3, + + Serial.println("RPM = " + String(avgRPM) + ", rotationTime ms = " + String(rotationTime * TIMER1_INTERVAL_MS) ); + + rotationTime = 0; + debounceCounter = 0; + } + else + debounceCounter++; + } + else + { + debounceCounter++; + } + + if (rotationTime >= 5000) + { + // If idle, set RPM to 0, don't increase rotationTime + RPM = 0; + Serial.println("RPM = " + String(RPM) + ", rotationTime = " + String(rotationTime) ); + rotationTime = 0; + } + else + { + rotationTime++; + } +} + +void setup() +{ + pinMode(interruptPin, INPUT_PULLUP); + + Serial.begin(115200); + while (!Serial); + + Serial.println("\nStarting ISR_RPM_Measure on " + String(BOARD_NAME)); + Serial.println("Version : " + String(NRF52_TIMER_INTERRUPT_VERSION)); + + // Interval in microsecs, must multiply to 1000 here or crash + if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1)) + Serial.println("Starting ITimer1 OK, millis() = " + String(millis())); + else + Serial.println("Can't set ITimer1. Select another freq., duration or timer"); + + // Assumming the interruptPin will go LOW + attachInterrupt(digitalPinToInterrupt(interruptPin), detectRotation, FALLING); +} + +void loop() +{ + +} diff --git a/examples/ISR_Timer_Complex_Ethernet/ISR_Timer_Complex_Ethernet.ino b/examples/ISR_Timer_Complex_Ethernet/ISR_Timer_Complex_Ethernet.ino new file mode 100644 index 0000000..f7e698d --- /dev/null +++ b/examples/ISR_Timer_Complex_Ethernet/ISR_Timer_Complex_Ethernet.ino @@ -0,0 +1,320 @@ +/**************************************************************************************************************************** + ISR_Timer_Complex_Ethernet.ino + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ +/* + Notes: + Special design is necessary to share data between interrupt code and the rest of your program. + Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume + variable can not spontaneously change. Because your function may change variables while your program is using them, + the compiler needs this hint. But volatile alone is often not enough. + When accessing shared variables, usually interrupts must be disabled. Even with volatile, + if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly. + If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled + or the entire sequence of your code which accesses the data. + + RPM Measuring uses high frequency hardware timer 1Hz == 1ms) to measure the time from of one rotation, in ms + then convert to RPM. One rotation is detected by reading the state of a magnetic REED SW or IR LED Sensor + Asssuming LOW is active. + For example: Max speed is 600RPM => 10 RPS => minimum 100ms a rotation. We'll use 80ms for debouncing + If the time between active state is less than 8ms => consider noise. + RPM = 60000 / (rotation time in ms) + + We use interrupt to detect whenever the SW is active, set a flag then use timer to count the time between active state + + This example will demonstrate the nearly perfect accuracy compared to software timers by printing the actual elapsed millisecs. + Being ISR-based timers, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet + and Blynk services. You can also have many (up to 16) timers to use. + This non-being-blocked important feature is absolutely necessary for mission-critical tasks. + You'll see blynkTimer is blocked while connecting to WiFi / Internet / Blynk, and elapsed time is very unaccurate + In this super simple example, you don't see much different after Blynk is connected, because of no competing task is + written +*/ + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +#define BLYNK_PRINT Serial + +//#define BLYNK_DEBUG +#ifdef BLYNK_DEBUG + #undef BLYNK_DEBUG +#endif + +/* Comment this out to disable prints and save space */ +#define BLYNK_PRINT Serial + +// If don't use USE_UIP_ETHERNET => use W5x00 with Ethernet library +#define USE_UIP_ETHERNET false + +#if (USE_UIP_ETHERNET) + #define ETHERNET_NAME "ENC28J60 Ethernet Shield" +#else + #define ETHERNET_NAME "W5x00 Ethernet Shield" +#endif + +#define BLYNK_NO_YIELD + +#if USE_UIP_ETHERNET + #include +#else + #include +#endif + +#define USE_LOCAL_SERVER true + +#if USE_LOCAL_SERVER + char auth[] = "******"; + char server[] = "account.duckdns.org"; + //char server[] = "192.168.2.112"; + +#else + char auth[] = "******"; + char server[] = "blynk-cloud.com"; +#endif + + #define BLYNK_HARDWARE_PORT 8080 + +#if !(USE_UIP_ETHERNET) + #define W5100_CS 10 + #define SDCARD_CS 4 +#endif + +// These define's must be placed at the beginning before #include "NRF52TimerInterrupt.h" +#define NRF52_TIMER_INTERRUPT_DEBUG 1 + +#include "NRF52TimerInterrupt.h" +#include "NRF52_ISR_Timer.h" + +#define HW_TIMER_INTERVAL_MS 1 + +volatile uint32_t lastMillis = 0; + +// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4) +// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1 + +// Init NRF52 timer NRF_TIMER1 +NRF52Timer ITimer(NRF_TIMER_2); + +// Init NRF52_ISR_Timer +// Each NRF52_ISR_Timer can service 16 different ISR-based timers +NRF52_ISR_Timer ISR_Timer; + +// Ibit Blynk Timer +BlynkTimer blynkTimer; + +#ifndef LED_BUILTIN + #define LED_BUILTIN PB0 // Pin 33/PB0 control on-board LED_GREEN on F767ZI +#endif + +#define LED_TOGGLE_INTERVAL_MS 5000L + +#define TIMER_INTERVAL_2S 2000L +#define TIMER_INTERVAL_5S 5000L +#define TIMER_INTERVAL_11S 11000L +#define TIMER_INTERVAL_21S 21000L + +void TimerHandler(void) +{ + static bool toggle = false; + static bool started = false; + static int timeRun = 0; + + ISR_Timer.run(); + + // Toggle LED every LED_TOGGLE_INTERVAL_MS = 5000ms = 5s + if (++timeRun == (LED_TOGGLE_INTERVAL_MS / HW_TIMER_INTERVAL_MS) ) + { + timeRun = 0; + + if (!started) + { + started = true; + pinMode(LED_BUILTIN, OUTPUT); + } + + //timer interrupt toggles pin LED_BUILTIN + digitalWrite(LED_BUILTIN, toggle); + toggle = !toggle; + } +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething2s() +{ + static unsigned long previousMillis = lastMillis; + unsigned long deltaMillis = millis() - previousMillis; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + if (previousMillis > TIMER_INTERVAL_2S) + { + Serial.print("2s: Delta ms = "); + Serial.println(deltaMillis); + } +#endif + + previousMillis = millis(); +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething5s() +{ + static unsigned long previousMillis = lastMillis; + unsigned long deltaMillis = millis() - previousMillis; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + if (previousMillis > TIMER_INTERVAL_5S) + { + Serial.print("5s: Delta ms = "); + Serial.println(deltaMillis); + } +#endif + + previousMillis = millis(); +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething11s() +{ + static unsigned long previousMillis = lastMillis; + unsigned long deltaMillis = millis() - previousMillis; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + if (previousMillis > TIMER_INTERVAL_11S) + { + Serial.print("11s: Delta ms = "); + Serial.println(deltaMillis); + } +#endif + + previousMillis = millis(); +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething21s() +{ + static unsigned long previousMillis = lastMillis; + unsigned long deltaMillis = millis() - previousMillis; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + if (previousMillis > TIMER_INTERVAL_21S) + { + Serial.print("21s: Delta ms = "); + Serial.println(deltaMillis); + } +#endif + + previousMillis = millis(); +} + +#define BLYNK_TIMER_MS 2000L + +// Here is software Timer, you can do somewhat fancy stuffs without many issues. +// But always avoid +// 1. Long delay() it just doing nothing and pain-without-gain wasting CPU power.Plan and design your code / strategy ahead +// 2. Very long "do", "while", "for" loops without predetermined exit time. +void blynkDoingSomething2s() +{ + static unsigned long previousMillis = lastMillis; + Serial.println("blynkDoingSomething2s: Delta programmed ms = " + String(BLYNK_TIMER_MS) + ", actual = " + String(millis() - previousMillis)); + previousMillis = millis(); +} + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + Serial.println("\nStarting ISR_Timer_Complex_Ethernet on " + String(BOARD_NAME)); + Serial.println("Version : " + String(NRF52_TIMER_INTERRUPT_VERSION)); + + // You need this timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary. + blynkTimer.setInterval(BLYNK_TIMER_MS, blynkDoingSomething2s); + + // Interval in microsecs + if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_MS * 1000, TimerHandler)) + { + lastMillis = millis(); + Serial.println("Starting ITimer OK, millis() = " + String(lastMillis)); + } + else + Serial.println("Can't set ITimer correctly. Select another freq. or interval"); + + // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary + // You can use up to 16 timer for each ISR_Timer + ISR_Timer.setInterval(TIMER_INTERVAL_2S, doingSomething2s); + ISR_Timer.setInterval(TIMER_INTERVAL_5S, doingSomething5s); + ISR_Timer.setInterval(TIMER_INTERVAL_11S, doingSomething11s); + ISR_Timer.setInterval(TIMER_INTERVAL_21S, doingSomething21s); + +#if !(USE_BUILTIN_ETHERNET || USE_UIP_ETHERNET) + pinMode(SDCARD_CS, OUTPUT); + digitalWrite(SDCARD_CS, HIGH); // Deselect the SD card +#endif + +#if USE_LOCAL_SERVER + Blynk.begin(auth, server, BLYNK_HARDWARE_PORT); +#else + Blynk.begin(auth); + // You can also specify server: + //Blynk.begin(auth, server, BLYNK_HARDWARE_PORT); +#endif + + if (Blynk.connected()) + { + Serial.print(F("IP = ")); + Serial.println(Ethernet.localIP()); + } +} + +#define BLOCKING_TIME_MS 3000L + +void loop() +{ + Blynk.run(); + + // This unadvised blocking task is used to demonstrate the blocking effects onto the execution and accuracy to Software timer + // You see the time elapse of ISR_Timer still accurate, whereas very unaccurate for Software Timer + // The time elapse for 2000ms software timer now becomes 3000ms (BLOCKING_TIME_MS) + // While that of ISR_Timer is still prefect. + delay(BLOCKING_TIME_MS); + + // You need this Software timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary + // You don't need to and never call ISR_Timer.run() here in the loop(). It's already handled by ISR timer. + blynkTimer.run(); +} diff --git a/examples/ISR_Timer_Complex_WiFiNINA/ISR_Timer_Complex_WiFiNINA.ino b/examples/ISR_Timer_Complex_WiFiNINA/ISR_Timer_Complex_WiFiNINA.ino new file mode 100644 index 0000000..1c7ccce --- /dev/null +++ b/examples/ISR_Timer_Complex_WiFiNINA/ISR_Timer_Complex_WiFiNINA.ino @@ -0,0 +1,309 @@ +/**************************************************************************************************************************** + ISR_Timer_Complex_WiFiNINA.ino + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ +/* + Notes: + Special design is necessary to share data between interrupt code and the rest of your program. + Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume + variable can not spontaneously change. Because your function may change variables while your program is using them, + the compiler needs this hint. But volatile alone is often not enough. + When accessing shared variables, usually interrupts must be disabled. Even with volatile, + if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly. + If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled + or the entire sequence of your code which accesses the data. + + RPM Measuring uses high frequency hardware timer 1Hz == 1ms) to measure the time from of one rotation, in ms + then convert to RPM. One rotation is detected by reading the state of a magnetic REED SW or IR LED Sensor + Asssuming LOW is active. + For example: Max speed is 600RPM => 10 RPS => minimum 100ms a rotation. We'll use 80ms for debouncing + If the time between active state is less than 8ms => consider noise. + RPM = 60000 / (rotation time in ms) + + We use interrupt to detect whenever the SW is active, set a flag then use timer to count the time between active state + + This example will demonstrate the nearly perfect accuracy compared to software timers by printing the actual elapsed millisecs. + Being ISR-based timers, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet + and Blynk services. You can also have many (up to 16) timers to use. + This non-being-blocked important feature is absolutely necessary for mission-critical tasks. + You'll see blynkTimer is blocked while connecting to WiFi / Internet / Blynk, and elapsed time is very unaccurate + In this super simple example, you don't see much different after Blynk is connected, because of no competing task is + written +*/ + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +#define BLYNK_PRINT Serial + +//#define BLYNK_DEBUG +#ifdef BLYNK_DEBUG + #undef BLYNK_DEBUG +#endif + +/* Comment this out to disable prints and save space */ +#define BLYNK_PRINT Serial + +#include + +#define USE_LOCAL_SERVER true + +#if USE_LOCAL_SERVER + char auth[] = "******"; + char server[] = "account.duckdns.org"; + //char server[] = "192.168.2.112"; + +#else + char auth[] = "******"; + char server[] = "blynk-cloud.com"; +#endif + + #define BLYNK_HARDWARE_PORT 8080 + +#if !(USE_BUILTIN_ETHERNET || USE_UIP_ETHERNET) + #define W5100_CS 10 + #define SDCARD_CS 4 +#endif + +// Your WiFi credentials. +char ssid[] = "SSID"; +char pass[] = "12345678"; + +// These define's must be placed at the beginning before #include "NRF52TimerInterrupt.h" +#define NRF52_TIMER_INTERRUPT_DEBUG 1 + +#include "NRF52TimerInterrupt.h" +#include "NRF52_ISR_Timer.h" + +#define HW_TIMER_INTERVAL_MS 1 + +volatile uint32_t lastMillis = 0; + +// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4) +// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1 + +// Init NRF52 timer NRF_TIMER1 +NRF52Timer ITimer(NRF_TIMER_2); + +// Init NRF52_ISR_Timer +// Each NRF52_ISR_Timer can service 16 different ISR-based timers +NRF52_ISR_Timer ISR_Timer; + +// Init Blynk Timer +BlynkTimer blynkTimer; + +#define LED_TOGGLE_INTERVAL_MS 5000L + +#define TIMER_INTERVAL_2S 2000L +#define TIMER_INTERVAL_5S 5000L +#define TIMER_INTERVAL_11S 11000L +#define TIMER_INTERVAL_101S 101000L + +void TimerHandler(void) +{ + static bool toggle = false; + static bool started = false; + static int timeRun = 0; + + ISR_Timer.run(); + + // Toggle LED every LED_TOGGLE_INTERVAL_MS = 5000ms = 5s + if (++timeRun == (LED_TOGGLE_INTERVAL_MS / HW_TIMER_INTERVAL_MS) ) + { + timeRun = 0; + + if (!started) + { + started = true; + pinMode(LED_BUILTIN, OUTPUT); + } + + //timer interrupt toggles pin LED_BUILTIN + digitalWrite(LED_BUILTIN, toggle); + toggle = !toggle; + } +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething2s() +{ + static unsigned long previousMillis = lastMillis; + unsigned long deltaMillis = millis() - previousMillis; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + if (previousMillis > TIMER_INTERVAL_2S) + { + Serial.print("2s: Delta ms = "); + Serial.println(deltaMillis); + } +#endif + + previousMillis = millis(); +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething5s() +{ + static unsigned long previousMillis = lastMillis; + unsigned long deltaMillis = millis() - previousMillis; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + if (previousMillis > TIMER_INTERVAL_5S) + { + Serial.print("5s: Delta ms = "); + Serial.println(deltaMillis); + } +#endif + + previousMillis = millis(); +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething11s() +{ + static unsigned long previousMillis = lastMillis; + unsigned long deltaMillis = millis() - previousMillis; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + if (previousMillis > TIMER_INTERVAL_11S) + { + Serial.print("11s: Delta ms = "); + Serial.println(deltaMillis); + } +#endif + + previousMillis = millis(); +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething101s() +{ + static unsigned long previousMillis = lastMillis; + unsigned long deltaMillis = millis() - previousMillis; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + if (previousMillis > TIMER_INTERVAL_101S) + { + Serial.print("101s: Delta ms = "); + Serial.println(deltaMillis); + } +#endif + + previousMillis = millis(); +} + +#define BLYNK_TIMER_MS 2000L + +// Here is software Timer, you can do somewhat fancy stuffs without many issues. +// But always avoid +// 1. Long delay() it just doing nothing and pain-without-gain wasting CPU power.Plan and design your code / strategy ahead +// 2. Very long "do", "while", "for" loops without predetermined exit time. +void blynkDoingSomething2s() +{ + static unsigned long previousMillis = lastMillis; + Serial.println("blynkDoingSomething2s: Delta programmed ms = " + String(BLYNK_TIMER_MS) + ", actual = " + String(millis() - previousMillis)); + previousMillis = millis(); +} + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + Serial.println("\nStarting ISR_Timer_Complex_WiFiNINA on " + String(BOARD_NAME)); + Serial.println("Version : " + String(NRF52_TIMER_INTERRUPT_VERSION)); + + // You need this timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary. + blynkTimer.setInterval(BLYNK_TIMER_MS, blynkDoingSomething2s); + + // Interval in microsecs + if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_MS * 1000, TimerHandler)) + { + lastMillis = millis(); + Serial.println("Starting ITimer OK, millis() = " + String(lastMillis)); + } + else + Serial.println("Can't set ITimer correctly. Select another freq. or interval"); + + // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary + // You can use up to 16 timer for each ISR_Timer + ISR_Timer.setInterval(TIMER_INTERVAL_2S, doingSomething2s); + ISR_Timer.setInterval(TIMER_INTERVAL_5S, doingSomething5s); + ISR_Timer.setInterval(TIMER_INTERVAL_11S, doingSomething11s); + ISR_Timer.setInterval(TIMER_INTERVAL_101S, doingSomething101s); + +#if !(USE_BUILTIN_ETHERNET || USE_UIP_ETHERNET) + pinMode(SDCARD_CS, OUTPUT); + digitalWrite(SDCARD_CS, HIGH); // Deselect the SD card +#endif + +#if USE_LOCAL_SERVER + //Blynk.begin(auth, server, BLYNK_HARDWARE_PORT); + Serial.println(F("Start Blynk")); + Blynk.begin(auth, ssid, pass, server, BLYNK_HARDWARE_PORT); +#else + Blynk.begin(auth); + // You can also specify server: + //Blynk.begin(auth, server, BLYNK_HARDWARE_PORT); +#endif + + if (Blynk.connected()) + { + Serial.print(F("IP = ")); + Serial.println(WiFi.localIP()); + } +} + +#define BLOCKING_TIME_MS 3000L + +void loop() +{ + static bool needWiFiBegin = true; + + Blynk.run(); + + // This unadvised blocking task is used to demonstrate the blocking effects onto the execution and accuracy to Software timer + // You see the time elapse of ISR_Timer still accurate, whereas very unaccurate for Software Timer + // The time elapse for 2000ms software timer now becomes 3000ms (BLOCKING_TIME_MS) + // While that of ISR_Timer is still prefect. + delay(BLOCKING_TIME_MS); + + // You need this Software timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary + // You don't need to and never call ISR_Timer.run() here in the loop(). It's already handled by ISR timer. + blynkTimer.run(); +} diff --git a/examples/RPM_Measure/RPM_Measure.ino b/examples/RPM_Measure/RPM_Measure.ino new file mode 100644 index 0000000..3ee2502 --- /dev/null +++ b/examples/RPM_Measure/RPM_Measure.ino @@ -0,0 +1,164 @@ +/**************************************************************************************************************************** + RPM_Measure.ino + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ +/* + Notes: + Special design is necessary to share data between interrupt code and the rest of your program. + Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume + variable can not spontaneously change. Because your function may change variables while your program is using them, + the compiler needs this hint. But volatile alone is often not enough. + When accessing shared variables, usually interrupts must be disabled. Even with volatile, + if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly. + If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled + or the entire sequence of your code which accesses the data. + + RPM Measuring uses high frequency hardware timer 1Hz == 1ms) to measure the time from of one rotation, in ms + then convert to RPM. One rotation is detected by reading the state of a magnetic REED SW or IR LED Sensor + Asssuming LOW is active. + For example: Max speed is 600RPM => 10 RPS => minimum 100ms a rotation. We'll use 80ms for debouncing + If the time between active state is less than 8ms => consider noise. + RPM = 60000 / (rotation time in ms) + + We use interrupt to detect whenever the SW is active, set a flag then use timer to count the time between active state + + RPM Measuring uses high frequency hardware timer 1Hz == 1ms) to measure the time from of one rotation, in ms + then convert to RPM. One rotation is detected by reading the state of a magnetic REED SW or IR LED Sensor + Asssuming LOW is active. + For example: Max speed is 600RPM => 10 RPS => minimum 100ms a rotation. We'll use 80ms for debouncing + If the time between active state is less than 8ms => consider noise. + RPM = 60000 / (rotation time in ms) + + You can also use interrupt to detect whenever the SW is active, set a flag then use timer to count the time between active state +*/ + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +// These define's must be placed at the beginning before #include "NRF52TimerInterrupt.h" +// Don't define NRF52_TIMER_INTERRUPT_DEBUG > 2. Only for special ISR debugging only. Can hang the system. +#define NRF52_TIMER_INTERRUPT_DEBUG 1 + +#include "NRF52TimerInterrupt.h" + +//#ifndef LED_BUILTIN +// #define LED_BUILTIN 13 +//#endif + +#ifndef LED_BLUE + #define LED_BLUE 7 +#endif + +#ifndef LED_RED + #define LED_RED 8 +#endif + +unsigned int SWPin = 7; + +#define TIMER0_INTERVAL_MS 1 +#define DEBOUNCING_INTERVAL_MS 80 + +#define LOCAL_DEBUG 1 + +// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4) +// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1 + +// Init NRF52 timer NRF_TIMER1 +NRF52Timer ITimer(NRF_TIMER_1); + +volatile unsigned long rotationTime = 0; +float RPM = 0.00; +float avgRPM = 0.00; + +volatile int debounceCounter; + +void TimerHandler() +{ + static bool started = false; + + if (!started) + { + started = true; + pinMode(SWPin, INPUT_PULLUP); + } + + if ( !digitalRead(SWPin) && (debounceCounter >= DEBOUNCING_INTERVAL_MS / TIMER0_INTERVAL_MS ) ) + { + //min time between pulses has passed + RPM = (float) ( 60000.0f / ( rotationTime * TIMER0_INTERVAL_MS ) ); + + avgRPM = ( 2 * avgRPM + RPM) / 3, + + Serial.println("RPM = " + String(avgRPM) + ", rotationTime ms = " + String(rotationTime * TIMER0_INTERVAL_MS) ); + + rotationTime = 0; + debounceCounter = 0; + } + else + { + debounceCounter++; + } + + if (rotationTime >= 5000) + { + // If idle, set RPM to 0, don't increase rotationTime + RPM = 0; + Serial.println("RPM = " + String(RPM) + ", rotationTime = " + String(rotationTime) ); + rotationTime = 0; + } + else + { + rotationTime++; + } +} + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + delay(100); + + Serial.println("\nStarting RPM_Measure on " + String(BOARD_NAME)); + Serial.println("Version : " + String(NRF52_TIMER_INTERRUPT_VERSION)); + + // Interval in microsecs + if (ITimer.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler)) + Serial.println("Starting ITimer OK, millis() = " + String(millis())); + else + Serial.println("Can't set ITimer. Select another freq. or timer"); + + Serial.flush(); +} + +void loop() +{ + +} diff --git a/examples/SwitchDebounce/SwitchDebounce.ino b/examples/SwitchDebounce/SwitchDebounce.ino new file mode 100644 index 0000000..243455d --- /dev/null +++ b/examples/SwitchDebounce/SwitchDebounce.ino @@ -0,0 +1,193 @@ +/**************************************************************************************************************************** + SwitchDebounce.ino + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ +/* + Notes: + Special design is necessary to share data between interrupt code and the rest of your program. + Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume + variable can not spontaneously change. Because your function may change variables while your program is using them, + the compiler needs this hint. But volatile alone is often not enough. + When accessing shared variables, usually interrupts must be disabled. Even with volatile, + if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly. + If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled + or the entire sequence of your code which accesses the data. + + Switch Debouncing uses high frequency hardware timer 50Hz == 20ms) to measure the time from the SW is pressed, + debouncing time is 100ms => SW is considered pressed if timer count is > 5, then call / flag SW is pressed + When the SW is released, timer will count (debounce) until more than 50ms until consider SW is released. + We can set to flag or call a function whenever SW is pressed more than certain predetermined time, even before + SW is released. +*/ + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +// These define's must be placed at the beginning before #include "NRF52TimerInterrupt.h" +// Don't define NRF52_TIMER_INTERRUPT_DEBUG > 2. Only for special ISR debugging only. Can hang the system. +#define NRF52_TIMER_INTERRUPT_DEBUG 1 + +#include "NRF52TimerInterrupt.h" + +//#ifndef LED_BUILTIN +// #define LED_BUILTIN 13 +//#endif + +#ifndef LED_BLUE + #define LED_BLUE 7 +#endif + +#ifndef LED_RED + #define LED_RED 8 +#endif + +unsigned int SWPin = 11; + +#define TIMER1_INTERVAL_MS 20 +#define DEBOUNCING_INTERVAL_MS 100 +#define LONG_PRESS_INTERVAL_MS 5000 + +#define LOCAL_DEBUG 1 + +// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4) +// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1 + +// Init NRF52 timer NRF_TIMER1 +NRF52Timer ITimer(NRF_TIMER_1); + +volatile bool SWPressed = false; +volatile bool SWLongPressed = false; + +void TimerHandler(void) +{ + static unsigned int debounceCountSWPressed = 0; + static unsigned int debounceCountSWReleased = 0; + + static unsigned long SWPressedTime; + static unsigned long SWReleasedTime; + + static bool started = false; + + if (!started) + { + started = true; + pinMode(SWPin, INPUT_PULLUP); + } + + if ( (!digitalRead(SWPin)) ) + { + // Start debouncing counting debounceCountSWPressed and clear debounceCountSWReleased + debounceCountSWReleased = 0; + + if (++debounceCountSWPressed >= DEBOUNCING_INTERVAL_MS / TIMER1_INTERVAL_MS) + { + // Call and flag SWPressed + if (!SWPressed) + { + SWPressedTime = millis(); + +#if (LOCAL_DEBUG > 0) + Serial.println("SW Press, from millis() = " + String(SWPressedTime - DEBOUNCING_INTERVAL_MS)); +#endif + + SWPressed = true; + // Do something for SWPressed here in ISR + // But it's better to use outside software timer to do your job instead of inside ISR + //Your_Response_To_Press(); + } + + if (debounceCountSWPressed >= LONG_PRESS_INTERVAL_MS / TIMER1_INTERVAL_MS) + { + // Call and flag SWLongPressed + if (!SWLongPressed) + { +#if (LOCAL_DEBUG > 0) + Serial.println("SW Long Pressed, total time ms = " + String(millis()) + " - " + String(SWPressedTime - DEBOUNCING_INTERVAL_MS) + + " = " + String(millis() - SWPressedTime + DEBOUNCING_INTERVAL_MS) ); +#endif + + SWLongPressed = true; + // Do something for SWLongPressed here in ISR + // But it's better to use outside software timer to do your job instead of inside ISR + //Your_Response_To_Long_Press(); + } + } + } + } + else + { + // Start debouncing counting debounceCountSWReleased and clear debounceCountSWPressed + if ( SWPressed && (++debounceCountSWReleased >= DEBOUNCING_INTERVAL_MS / TIMER1_INTERVAL_MS)) + { + SWReleasedTime = millis(); + + // Call and flag SWPressed +#if (LOCAL_DEBUG > 0) + Serial.println("SW Released, from millis() = " + String(SWReleasedTime)); +#endif + + SWPressed = false; + SWLongPressed = false; + + // Do something for !SWPressed here in ISR + // But it's better to use outside software timer to do your job instead of inside ISR + //Your_Response_To_Release(); + + // Call and flag SWPressed +#if (LOCAL_DEBUG > 0) + Serial.println("SW Pressed total time ms = " + String(SWReleasedTime - SWPressedTime)); +#endif + + debounceCountSWPressed = 0; + } + } +} + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + delay(100); + + Serial.println("\nStarting SwitchDebounce on " + String(BOARD_NAME)); + Serial.println("Version : " + String(NRF52_TIMER_INTERRUPT_VERSION)); + + // Interval in microsecs + if (ITimer.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler)) + Serial.println("Starting ITimer OK, millis() = " + String(millis())); + else + Serial.println("Can't set ITimer. Select another freq., duration or timer"); +} + +void loop() +{ + +} diff --git a/examples/TimerInterruptLEDDemo/TimerInterruptLEDDemo.ino b/examples/TimerInterruptLEDDemo/TimerInterruptLEDDemo.ino new file mode 100644 index 0000000..63d4e70 --- /dev/null +++ b/examples/TimerInterruptLEDDemo/TimerInterruptLEDDemo.ino @@ -0,0 +1,143 @@ +/**************************************************************************************************************************** + TimerInterruptLEDDemo.ino + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ + +/* + Notes: + Special design is necessary to share data between interrupt code and the rest of your program. + Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume + variable can not spontaneously change. Because your function may change variables while your program is using them, + the compiler needs this hint. But volatile alone is often not enough. + When accessing shared variables, usually interrupts must be disabled. Even with volatile, + if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly. + If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled + or the entire sequence of your code which accesses the data. +*/ + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +// These define's must be placed at the beginning before #include "NRF52TimerInterrupt.h" +// Don't define NRF52_TIMER_INTERRUPT_DEBUG > 2. Only for special ISR debugging only. Can hang the system. +#define NRF52_TIMER_INTERRUPT_DEBUG 1 + +//#ifndef LED_BUILTIN +// #define LED_BUILTIN 3 +//#endif + +#ifndef LED_BLUE_PIN + #define LED_BLUE_PIN 7 +#endif + +#ifndef LED_RED + #define LED_RED 8 +#endif + +#include "NRF52TimerInterrupt.h" +#include "NRF52_ISR_Timer.h" + +#define HW_TIMER_INTERVAL_MS 1 + +// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4) +// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1 + +// Init NRF52 timer NRF_TIMER1 +NRF52Timer ITimer(NRF_TIMER_1); + +// Init NRF52_ISR_Timer +// Each NRF52_ISR_Timer can service 16 different ISR-based timers +NRF52_ISR_Timer ISR_Timer; + +#define TIMER_INTERVAL_1S 1000L +#define TIMER_INTERVAL_2S 2000L +#define TIMER_INTERVAL_5S 5000L + +void TimerHandler(void) +{ + ISR_Timer.run(); +} + +// In NRF52, avoid doing something fancy in ISR, for example complex Serial.print with String() argument +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment +// Or you can get this run-time error / crash +void doingSomething1() +{ + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); + Serial.println("G"); +} + +void doingSomething2() +{ + digitalWrite(LED_BLUE, !digitalRead(LED_BLUE)); + Serial.println("B"); +} +void doingSomething3() +{ + digitalWrite(LED_RED, !digitalRead(LED_RED)); + Serial.println("R"); +} + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + Serial.println("\nTimerInterruptLEDDemo on " + String(BOARD_NAME)); + Serial.println("CPU Frequency = " + String(F_CPU / 1000000) + " MHz"); + + // Instantiate HardwareTimer object. Thanks to 'new' instanciation, HardwareTimer is not destructed when setup() function is finished. + //HardwareTimer *MyTim = new HardwareTimer(Instance); + + // configure pin in output mode + pinMode(LED_BUILTIN, OUTPUT); + pinMode(LED_BLUE, OUTPUT); + pinMode(LED_RED, OUTPUT); + + // Interval in microsecs + if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_MS * 1000, TimerHandler)) + { + Serial.println("Starting ITimer OK, millis() = " + String(millis())); + } + else + Serial.println("Can't set ITimer correctly. Select another freq. or interval"); + + // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary + // You can use up to 16 timer for each ISR_Timer + ISR_Timer.setInterval(TIMER_INTERVAL_1S, doingSomething1); + ISR_Timer.setInterval(TIMER_INTERVAL_2S, doingSomething2); + ISR_Timer.setInterval(TIMER_INTERVAL_5S, doingSomething3); +} + + +void loop() +{ + /* Nothing to do all is done by hardware. Even no interrupt required. */ +} diff --git a/examples/TimerInterruptTest/TimerInterruptTest.ino b/examples/TimerInterruptTest/TimerInterruptTest.ino new file mode 100644 index 0000000..44d6387 --- /dev/null +++ b/examples/TimerInterruptTest/TimerInterruptTest.ino @@ -0,0 +1,215 @@ +/**************************************************************************************************************************** + TimerInterruptTest.ino + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ +/* + Notes: + Special design is necessary to share data between interrupt code and the rest of your program. + Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume + variable can not spontaneously change. Because your function may change variables while your program is using them, + the compiler needs this hint. But volatile alone is often not enough. + When accessing shared variables, usually interrupts must be disabled. Even with volatile, + if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly. + If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled + or the entire sequence of your code which accesses the data. +*/ + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +// These define's must be placed at the beginning before #include "NRF52TimerInterrupt.h" +// Don't define NRF52_TIMER_INTERRUPT_DEBUG > 2. Only for special ISR debugging only. Can hang the system. +#define NRF52_TIMER_INTERRUPT_DEBUG 1 + +#include "NRF52TimerInterrupt.h" + +//#ifndef LED_BUILTIN +// #define LED_BUILTIN 3 +//#endif + +#ifndef LED_BLUE_PIN + #define LED_BLUE_PIN 7 +#endif + +#ifndef LED_RED + #define LED_RED 8 +#endif + +unsigned int SWPin = 11; + +#define TIMER0_INTERVAL_MS 1000 +#define TIMER0_DURATION_MS 5000 + +#define TIMER1_INTERVAL_MS 3000 +#define TIMER1_DURATION_MS 15000 + +volatile uint32_t preMillisTimer0 = 0; +volatile uint32_t preMillisTimer1 = 0; + +// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4) +// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1 + +// Init NRF52 timer NRF_TIMER1 +NRF52Timer ITimer0(NRF_TIMER_1); + +void TimerHandler0(void) +{ + static bool toggle0 = false; + static bool started = false; + static uint32_t curMillis = 0; + + if (!started) + { + started = true; + pinMode(LED_BUILTIN, OUTPUT); + } + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + curMillis = millis(); + + if (curMillis > TIMER0_INTERVAL_MS) + { + Serial.println("ITimer0: millis() = " + String(curMillis) + ", delta = " + String(curMillis - preMillisTimer0)); + } + + preMillisTimer0 = curMillis; +#endif + + //timer interrupt toggles pin LED_BUILTIN + digitalWrite(LED_BUILTIN, toggle0); + toggle0 = !toggle0; +} + +// Init NRF52 timer NRF_TIMER2 +NRF52Timer ITimer1(NRF_TIMER_2); + +void TimerHandler1(void) +{ + static bool toggle1 = false; + static bool started = false; + static uint32_t curMillis = 0; + + if (!started) + { + started = true; + pinMode(LED_BLUE, OUTPUT); + } + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + curMillis = millis(); + + if (curMillis > TIMER1_INTERVAL_MS) + { + Serial.println("ITimer1: millis() = " + String(curMillis) + ", delta = " + String(curMillis - preMillisTimer1)); + } + + preMillisTimer1 = curMillis; +#endif + + //timer interrupt toggles outputPin + digitalWrite(LED_BLUE, toggle1); + toggle1 = !toggle1; +} + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + delay(100); + + Serial.println("\nStarting TimerInterruptTest on " + String(BOARD_NAME)); + Serial.println("Version : " + String(NRF52_TIMER_INTERRUPT_VERSION)); + + // Interval in microsecs + if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0)) + { + preMillisTimer0 = millis(); + Serial.println("Starting ITimer1 OK, millis() = " + String(preMillisTimer0)); + } + else + Serial.println("Can't set ITimer0. Select another freq. or timer"); + + // Interval in microsecs + if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1)) + { + preMillisTimer1 = millis(); + Serial.println("Starting ITimer1 OK, millis() = " + String(preMillisTimer1)); + } + else + Serial.println("Can't set ITimer1. Select another freq. or timer"); +} + +void loop() +{ + static unsigned long lastTimer0 = 0; + static bool timer0Stopped = false; + + static unsigned long lastTimer1 = 0; + static bool timer1Stopped = false; + + + if (millis() - lastTimer0 > TIMER0_DURATION_MS) + { + lastTimer0 = millis(); + + if (timer0Stopped) + { + preMillisTimer0 = millis(); + Serial.println("Start ITimer0, millis() = " + String(preMillisTimer0)); + ITimer0.restartTimer(); + } + else + { + Serial.println("Stop ITimer0, millis() = " + String(millis())); + ITimer0.stopTimer(); + } + timer0Stopped = !timer0Stopped; + } + + if (millis() - lastTimer1 > TIMER1_DURATION_MS) + { + lastTimer1 = millis(); + + if (timer1Stopped) + { + preMillisTimer1 = millis(); + Serial.println("Start ITimer1, millis() = " + String(preMillisTimer1)); + ITimer1.restartTimer(); + } + else + { + Serial.println("Stop ITimer1, millis() = " + String(millis())); + ITimer1.stopTimer(); + } + + timer1Stopped = !timer1Stopped; + } +} diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..5ea99d3 --- /dev/null +++ b/keywords.txt @@ -0,0 +1,70 @@ +####################################### +# Datatypes (KEYWORD1) +####################################### + +NRF52TimerInterrupt KEYWORD1 +NRF52Timer KEYWORD1 +NRF52_ISRTimer KEYWORD1 +NRF52_ISR_Timer KEYWORD1 +NRF52TimerNumber KEYWORD1 +timer_callback KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +############################## +# Class NRF52TimerInterrupt +############################## + +setFrequency KEYWORD2 +setInterval KEYWORD2 +attachInterrupt KEYWORD2 +attachInterruptInterval KEYWORD2 +detachInterrupt KEYWORD2 +disableTimer KEYWORD2 +reattachInterrupt KEYWORD2 +enableTimer KEYWORD2 +stopTimer KEYWORD2 +restartTimer KEYWORD2 +getCallback KEYWORD2 +getTimerIRQn KEYWORD2 + +############################## +# Class NRF52_ISR_Timer +############################## + +run KEYWORD2 +setTimeout KEYWORD2 +setTimer KEYWORD2 +changeInterval KEYWORD2 +deleteTimer KEYWORD2 +restartTimer KEYWORD2 +isEnabled KEYWORD2 +enable KEYWORD2 +disable KEYWORD2 +enableAll KEYWORD2 +disableAll KEYWORD2 +toggle KEYWORD2 +getNumTimers KEYWORD2 +getNumAvailableTimers KEYWORD2 + +############################## +# Global Functions +############################## + +TIMER1_IRQHandler KEYWORD2 +TIMER2_IRQHandler KEYWORD2 +TIMER3_IRQHandler KEYWORD2 +TIMER4_IRQHandler KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +NRF_TIMER_0 LITERAL1 +NRF_TIMER_1 LITERAL1 +NRF_TIMER_2 LITERAL1 +NRF_TIMER_3 LITERAL1 +NRF_TIMER_4 LITERAL1 +NRF_MAX_TIMER LITERAL1 diff --git a/library.json b/library.json new file mode 100644 index 0000000..1ae4970 --- /dev/null +++ b/library.json @@ -0,0 +1,29 @@ +{ + "name": "NRF52_TimerInterrupt", + "version": "1.0.0", + "keywords": "timing,device,control,timer,interrupt,hardware,NRF52,mission-critical,precise,non-blocking,isr", + "description": "This library enables you to use Interrupt from Hardware Timers on an NRF52-based board. These hardware timers, using interrupt, still work even if other functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software timers using millis() or micros(). That's necessary if you need to measure some data requiring better accuracy.", + "authors": + { + "name": "Khoi Hoang", + "url": "https://github.com/khoih-prog", + "maintainer": true + }, + "repository": + { + "type": "git", + "url": "//https://github.com/khoih-prog/NRF52_TimerInterrupt" + }, + "homepage": "https://github.com/khoih-prog/NRF52_TimerInterrupt", + "export": { + "exclude": [ + "linux", + "extras", + "tests" + ] + }, + "frameworks": "*", + "platforms": "nordicnrf52", + "examples": "examples/*/*/*.ino", + "license": "MIT" +} diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..12b443d --- /dev/null +++ b/library.properties @@ -0,0 +1,12 @@ +name=NRF52_TimerInterrupt +version=1.0.0 +author=Khoi Hoang +maintainer=Khoi Hoang +sentence=This library enables you to use Interrupt from Hardware Timers on an NRF52-based board +paragraph=These NRF52 Hardware Timers, using Interrupt, still work even if other functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software timers using millis() or micros(). That's mandatory if you need to measure some data requiring better accuracy. It now supports 16 ISR-based Timers, while consuming only 1 Hardware Timer. Timers' interval is very long (ulong millisecs). The most important feature is they're ISR-based Timers. Therefore, their executions are not blocked by bad-behaving functions or tasks. This important feature is absolutely necessary for mission-critical tasks. +category=Timing,Control,Device,Time,Timer,NRF52,interrupt +url=https://github.com/khoih-prog/NRF52_TimerInterrupt +architectures=nordicnrf52 +repository=https://github.com/khoih-prog/NRF52_TimerInterrupt +license=MIT +includes=NRF52TimerInterrupt.h,NRF52_ISR_Timer.h diff --git a/platformio/platformio.ini b/platformio/platformio.ini new file mode 100644 index 0000000..2d53866 --- /dev/null +++ b/platformio/platformio.ini @@ -0,0 +1,336 @@ +;PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + + +[platformio] +; ============================================================ +; chose environment: +; ESP8266 +; ESP32 +; SAMD +; NRF52 +; STM32 +; ============================================================ +;default_envs = ESP8266 +;default_envs = ESP32 +;default_envs = SAMD +default_envs = NRF52 +;default_envs = STM32 + +[env] +; ============================================================ +; Serial configuration +; choose upload speed, serial-monitor speed +; ============================================================ +upload_speed = 921600 +;upload_port = COM11 +;monitor_speed = 9600 +;monitor_port = COM11 + +lib_deps = + +build_flags = +; set your debug output (default=Serial) +; -D DEBUG_ESP_PORT=Serial +; comment the folowing line to enable WiFi debugging +; -D NDEBUG + +[env:ESP8266] +platform = espressif8266 +framework = arduino +; ============================================================ +; Board configuration +; choose your board by uncommenting one of the following lines +; ============================================================ +;board = gen4iod +;board = huzzah +;board = oak +;board = esp_wroom_02 +;board = espduino +;board = espectro +;board = espino +;board = espresso_lite_v1 +;board = espresso_lite_v2 +;board = esp12e +;board = esp01_1m +;board = esp01 +;board = esp07 +;board = esp8285 +;board = heltec_wifi_kit_8 +;board = inventone +;board = nodemcu +board = nodemcuv2 +;board = modwifi +;board = phoenix_v1 +;board = phoenix_v2 +;board = sparkfunBlynk +;board = thing +;board = thingdev +;board = esp210 +;board = espinotee +;board = d1 +;board = d1_mini +;board = d1_mini_lite +;board = d1_mini_pro +;board = wifi_slot +;board = wifiduino +;board = wifinfo +;board = wio_link +;board = wio_node +;board = xinabox_cw01 +;board = esp32doit-devkit-v1 + +[env:ESP32] +platform = espressif32 +framework = arduino, espidf +; ============================================================ +; Board configuration +; choose your board by uncommenting one of the following lines +; ============================================================ +;board = esp32cam +;board = alksesp32 +;board = featheresp32 +;board = espea32 +;board = bpi-bit +;board = d-duino-32 +board = esp32doit-devkit-v1 +;board = pocket_32 +;board = fm-devkit +;board = pico32 +;board = esp32-evb +;board = esp32-gateway +;board = esp32-pro +;board = esp32-poe +;board = oroca_edubot +;board = onehorse32dev +;board = lopy +;board = lopy4 +;board = wesp32 +;board = esp32thing +;board = sparkfun_lora_gateway_1-channel +;board = ttgo-lora32-v1 +;board = ttgo-t-beam +;board = turta_iot_node +;board = lolin_d32 +;board = lolin_d32_pro +;board = lolin32 +;board = wemosbat +;board = widora-air +;board = xinabox_cw02 +;board = iotbusio +;board = iotbusproteus +;board = nina_w10 + +[env:SAMD] +platform = atmelsam +framework = arduino +; ============================================================ +; Choose your board by uncommenting one of the following lines +; ============================================================ +; ============================================================ +; Board configuration Adafruit SAMD +; ============================================================ + +;board = adafruit_feather_m0 +;board = adafruit_feather_m0_express +;board = adafruit_metro_m0 +;board = adafruit_circuitplayground_m0 +;board = adafruit_gemma_m0 +;board = adafruit_trinket_m0 +;board = adafruit_itsybitsy_m0 +;board = adafruit_pirkey +;board = adafruit_hallowing +;board = adafruit_crickit_m0 +;board = adafruit_metro_m4 +;board = adafruit_grandcentral_m4 +board = adafruit_itsybitsy_m4 +;board = adafruit_feather_m4 +;board = adafruit_trellis_m4 +;board = adafruit_pyportal_m4 +;board = adafruit_pyportal_m4_titano +;board = adafruit_pybadge_m4 +;board = adafruit_metro_m4_airliftlite +;board = adafruit_pygamer_m4 +;board = adafruit_pygamer_advance_m4 +;board = adafruit_pybadge_airlift_m4 +;board = adafruit_monster_m4sk +;board = adafruit_hallowing_m4 + +; ============================================================ +; Board configuration Arduino SAMD and SAM +; ============================================================ + +;board = arduino_zero_edbg +;board = arduino_zero_native +;board = mkr1000 +;board = mkrzero +;board = mkrwifi1010 +;board = nano_33_iot +;board = mkrfox1200 +;board = mkrwan1300 +;board = mkrwan1310 +;board = mkrgsm1400 +;board = mkrnb1500 +;board = mkrvidor4000 +;board = adafruit_circuitplayground_m0 +;board = mzero_pro_bl_dbg +;board = mzero_pro_bl +;board = mzero_bl +;board = tian +;board = tian_cons +;board = arduino_due_x_dbg +;board = arduino_due_x + +; ============================================================ +; Board configuration Seeeduino SAMD +; ============================================================ + +;board = seeed_wio_terminal +;board = Seeed_femto_m0 +;board = seeed_XIAO_m0 +;board = Wio_Lite_MG126 +;board = WioGPS +;board = zero +;board = rolawan +;board = seeed_grove_ui_wireless + + +[env:NRF52] +platform = nordicnrf52 +framework = arduino +; ============================================================ +; Board configuration Adafruit nRF52 +; choose your board by uncommenting one of the following lines +; ============================================================ +;board = feather52832 +board = feather52840 +;board = feather52840sense +;board = itsybitsy52840 +;board = cplaynrf52840 +;board = cluenrf52840 +;board = metro52840 +;board = pca10056 +;board = particle_xenon +;board = mdbt50qrx +;board = ninab302 +;board = ninab112 + +[env:STM32] +platform = ststm32 +framework = arduino + +; ============================================================ +; Choose your board by uncommenting one of the following lines +; ============================================================ + +; ============================================================ +; Board configuration Nucleo-144 +; ============================================================ + +;board = nucleo_f207zg +;board = nucleo_f429zi +;board = nucleo_f746zg +;board = nucleo_f756zg +;board = nucleo_f767zi +;board = nucleo_h743zi +;board = nucleo_l496zg +;board = nucleo_l496zg-p +;board = nucleo_l4r5zi +;board = nucleo_l4r5zi-p + +; ============================================================ +; Board configuration Nucleo-64 +; ============================================================ + +;board = nucleo_f030r8 +;board = nucleo_f072rb + +;board = nucleo_f091rc +;board = nucleo_f103rb +;board = nucleo_f302r8 +;board = nucleo_f303re +;board = nucleo_f401re +;board = nucleo_f411re +;board = nucleo_f446re +;board = nucleo_g071rb +;board = nucleo_g431rb +;board = nucleo_g474re +;board = nucleo_l053r8 +;board = nucleo_l073rz +;board = nucleo_l152re +;board = nucleo_l433rc_p +;board = nucleo_l452re +;board = nucleo_l452re-p +;board = nucleo_l476rg +;board = pnucleo_wb55rg + +; ============================================================ +; Board configuration Nucleo-32 +; ============================================================ + +;board = nucleo_f031k6 +;board = nucleo_l031k6 +;board = nucleo_l412kb +;board = nucleo_l432lc +;board = nucleo_f303k8 +;board = nucleo_g431kb + +; ============================================================ +; Board configuration Discovery Boards +; ============================================================ + +;board = disco_f030r8 +;board = disco_f072rb +;board = disco_f030r8 +;board = disco_f100rb +;board = disco_f407vg +;board = disco_f413zh +;board = disco_f746ng +;board = disco_g0316 +;board = disco_l475vg_iot +;board = disco_f072cz-lrwan1 + +; ============================================================ +; Board configuration STM32MP1 Boards +; ============================================================ + +;board = stm32mp157a-dk1 +;board = stm32mp157c-dk2 + +; ============================================================ +; Board configuration Generic Boards +; ============================================================ + +;board = bluepill_f103c6 +;board = bluepill_f103c8 +;board = blackpill_f103c8 +;board = stm32f103cx +;board = stm32f103rx +;board = stm32f103tx +;board = stm32f103vx +;board = stm32f103zx +;board = stm32f103zet6 +;board = maplemini_f103cb +;board = blackpill_f303cc +;board = black_f407ve +;board = black_f407vg +;board = black_f407ze +;board = black_f407zg +;board = blue_f407ve_mini +;board = blackpill_f401cc +;board = blackpill_f411ce +;board = coreboard_f401rc +;board = feather_f405 + +; ============================================================ +; Board configuration Many more Boards to be filled +; ============================================================ + + diff --git a/src/NRF52TimerInterrupt.h b/src/NRF52TimerInterrupt.h new file mode 100644 index 0000000..8308862 --- /dev/null +++ b/src/NRF52TimerInterrupt.h @@ -0,0 +1,390 @@ +/**************************************************************************************************************************** + NRF52TimerInterrupt.h + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ +/* + nRF52 has 5 Hardware TIMERs: NRF_TIMER0-NRF_TIMER4 + NRF_TIMER0 is used by the soft device, NRF_TIMER1-NRF_TIMER4 are available + + Defined in file ./adafruit/hardware/nrf52/0.21.0/cores/nRF5/nordic/nrfx/mdk/nrf52.h + + #define NRF_TIMER0_BASE 0x40008000UL + #define NRF_TIMER1_BASE 0x40009000UL + #define NRF_TIMER2_BASE 0x4000A000UL + #define NRF_TIMER3_BASE 0x4001A000UL + #define NRF_TIMER4_BASE 0x4001B000UL + ... + #define NRF_TIMER0 ((NRF_TIMER_Type*) NRF_TIMER0_BASE) + #define NRF_TIMER1 ((NRF_TIMER_Type*) NRF_TIMER1_BASE) + #define NRF_TIMER2 ((NRF_TIMER_Type*) NRF_TIMER2_BASE) + #define NRF_TIMER3 ((NRF_TIMER_Type*) NRF_TIMER3_BASE) + #define NRF_TIMER4 ((NRF_TIMER_Type*) NRF_TIMER4_BASE) + + =============================================================================== + + Defined in ./adafruit/hardware/nrf52/0.21.0/cores/nRF5/nordic/nrfx/hal/nrf_timer.h + + Timer prescalers + typedef enum + { + NRF_TIMER_FREQ_16MHz = 0, ///< Timer frequency 16 MHz. + NRF_TIMER_FREQ_8MHz, ///< Timer frequency 8 MHz. + NRF_TIMER_FREQ_4MHz, ///< Timer frequency 4 MHz. + NRF_TIMER_FREQ_2MHz, ///< Timer frequency 2 MHz. + NRF_TIMER_FREQ_1MHz, ///< Timer frequency 1 MHz. + NRF_TIMER_FREQ_500kHz, ///< Timer frequency 500 kHz. + NRF_TIMER_FREQ_250kHz, ///< Timer frequency 250 kHz. + NRF_TIMER_FREQ_125kHz, ///< Timer frequency 125 kHz. + NRF_TIMER_FREQ_62500Hz, ///< Timer frequency 62500 Hz. + NRF_TIMER_FREQ_31250Hz ///< Timer frequency 31250 Hz. + } nrf_timer_frequency_t; + +*/ +#pragma once + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +#include +#include "nrf_timer.h" + +#define NRF52_TIMER_INTERRUPT_VERSION "1.0.0" + +#ifndef NRF52_TIMER_INTERRUPT_DEBUG + #define NRF52_TIMER_INTERRUPT_DEBUG 0 +#endif + +class NRF52TimerInterrupt; + +typedef NRF52TimerInterrupt NRF52Timer; + +typedef void (*timer_callback) (void); + +typedef enum +{ + NRF_TIMER_0 = 0, + NRF_TIMER_1 = 1, + NRF_TIMER_2 = 2, + NRF_TIMER_3 = 3, + NRF_TIMER_4 = 4, + NRF_MAX_TIMER +} NRF52TimerNumber; + +const char* NRF52TimerName[NRF_MAX_TIMER] = +{ + "NRF_TIMER0-DON'T_USE_THIS", + "NRF_TIMER1", + "NRF_TIMER2", + "NRF_TIMER3", + "NRF_TIMER4", +}; + +/* +typedef enum +{ + NRF_TIMER_CC_CHANNEL0 = 0, ///< Timer capture/compare channel 0. + NRF_TIMER_CC_CHANNEL1, ///< Timer capture/compare channel 1. + NRF_TIMER_CC_CHANNEL2, ///< Timer capture/compare channel 2. + NRF_TIMER_CC_CHANNEL3, ///< Timer capture/compare channel 3. +#ifdef NRF52 + NRF_TIMER_CC_CHANNEL4, ///< Timer capture/compare channel 4. + NRF_TIMER_CC_CHANNEL5, ///< Timer capture/compare channel 5. +#endif +} nrf_timer_cc_channel_t; +*/ + +class NRF52TimerInterrupt; + +NRF_TIMER_Type* nrf_timers [NRF_MAX_TIMER] = { NRF_TIMER0, NRF_TIMER1, NRF_TIMER2, NRF_TIMER3, NRF_TIMER4 }; + +IRQn_Type nrf_timers_irq[NRF_MAX_TIMER] = { TIMER0_IRQn, TIMER1_IRQn, TIMER2_IRQn, TIMER3_IRQn, TIMER4_IRQn }; + +NRF52TimerInterrupt* nRF52Timers [NRF_MAX_TIMER] = { NULL, NULL, NULL, NULL, NULL }; + + +class NRF52TimerInterrupt +{ + private: + uint8_t _timer = NRF_TIMER_1; + + NRF_TIMER_Type* nrf_timer = NRF_TIMER1; + nrf_timer_cc_channel_t cc_channel = NRF_TIMER_CC_CHANNEL0; + + IRQn_Type _timer_IRQ; + + timer_callback _callback; // pointer to the callback function + + // NRF_TIMER_FREQ_16MHz,NRF_TIMER_FREQ_8MHz,...,NRF_TIMER_FREQ_31250Hz + nrf_timer_frequency_t _frequency_t = NRF_TIMER_FREQ_1MHz; + float _frequency; // Timer frequency + uint32_t _timerCount; // count to activate timer + + public: + + NRF52TimerInterrupt(uint8_t timer = NRF_TIMER_1) + { + // KH, force to use NRF_TIMER1 if accidentally select already used NRF_TIMER0 + // To store to know which to delete in destructor + if (timer == NRF_TIMER_0) + _timer = NRF_TIMER_1; + else + _timer = timer; + + nrf_timer = nrf_timers[_timer]; + + _timer_IRQ = nrf_timers_irq[_timer]; + + // Update to use in TIMERx_IRQHandler + nRF52Timers[_timer] = this; + + _callback = NULL; + + // Timer mode with 32bit width + nrf_timer_bit_width_set(nrf_timer, NRF_TIMER_BIT_WIDTH_32); + nrf_timer_mode_set(nrf_timer, NRF_TIMER_MODE_TIMER); + + // KH, just 1MHz is enough. 16MHz can have better accuracy, but shorter time range. + nrf_timer_frequency_set(nrf_timer, _frequency_t); + + switch (_frequency_t) + { + case NRF_TIMER_FREQ_16MHz: + _frequency = 16000000.0f; + + break; + case NRF_TIMER_FREQ_8MHz: + _frequency = 8000000.0f; + + break; + case NRF_TIMER_FREQ_4MHz: + _frequency = 4000000.0f; + + break; + case NRF_TIMER_FREQ_2MHz: + _frequency = 2000000.0f; + + break; + case NRF_TIMER_FREQ_1MHz: + _frequency = 1000000.0f; + + break; + default: + _frequency = 1000000.0f; + break; + } + }; + + ~NRF52TimerInterrupt() + { + nRF52Timers[_timer] = NULL; + } + + // frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely + // No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c + bool setFrequency(float frequency, timer_callback callback) + { + // This function will be called when time out interrupt will occur + if (callback) + { + _callback = callback; + } + else + { + Serial.println("NRF52TimerInterrupt: ERROR: NULL callback function pointer."); + return false; + } + + if ( (frequency <= 0) || (frequency > _frequency / 10.0f) ) + { + Serial.println("NRF52TimerInterrupt: ERROR: Negative or Too high frequency. Must be <= " + String(_frequency/10.0f)); + return false; + } + + // select timer frequency is 1MHz for better accuracy. We don't use 16-bit prescaler for now. + // Will use later if very low frequency is needed. + _timerCount = (uint32_t) _frequency / frequency; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + Serial.println("NRF52TimerInterrupt: F_CPU (MHz) = " + String(F_CPU/1000000) + ", Timer = " + NRF52TimerName[_timer] ); + Serial.println("NRF52TimerInterrupt: _fre = " + String(_frequency) + ", _count = " + String((uint32_t) (_timerCount))); +#endif + + // Start if not already running (and reset?) + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_START); + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_CLEAR); + + // Clear and enable compare interrupt + nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel); + nrf_timer_int_enable(nrf_timer, channel_mask); + + NVIC_EnableIRQ(_timer_IRQ); + + //nrf_timer_cc_write(nrf_timer, cc_channel, _timerCount); + // New for Adafruit nRF52 core 0.21.0 + nrf_timer_cc_set(nrf_timer, cc_channel, _timerCount); + + return true; + } + + // interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely + // No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c + bool setInterval(unsigned long interval, timer_callback callback) + { + return setFrequency((float) (1000000.0f / interval), callback); + } + + bool attachInterrupt(float frequency, timer_callback callback) + { + return setFrequency(frequency, callback); + } + + // interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely + // No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c + bool attachInterruptInterval(unsigned long interval, timer_callback callback) + { + return setFrequency( (float) ( 1000000.0f / interval), callback); + } + + void detachInterrupt(void) + { + NVIC_DisableIRQ(_timer_IRQ); + + // Stop timer + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_STOP); + + // Disable timer compare interrupt + nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel); + nrf_timer_int_disable(nrf_timer, channel_mask); + + // Clear event + nrf_timer_event_t event = nrf_timer_compare_event_get(channel_mask); + nrf_timer_event_clear(nrf_timer, event); + } + + void disableTimer(void) + { + detachInterrupt(); + } + + // Duration (in milliseconds). Duration = 0 or not specified => run indefinitely + void reattachInterrupt() + { + setFrequency(_frequency, _callback); + } + + // Duration (in milliseconds). Duration = 0 or not specified => run indefinitely + void enableTimer(void) + { + // Start if not already running (and reset?) + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_START); + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_CLEAR); + + // Clear and enable compare interrupt + nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel); + nrf_timer_int_enable(nrf_timer, channel_mask); + + NVIC_EnableIRQ(_timer_IRQ); + + //nrf_timer_cc_write(nrf_timer, cc_channel, _timerCount); + // New for Adafruit nRF52 core 0.21.0 + nrf_timer_cc_set(nrf_timer, cc_channel, _timerCount); + } + + // Just stop clock source, clear the count + void stopTimer(void) + { + disableTimer(); + } + + // Just reconnect clock source, start current count from 0 + void restartTimer(void) + { + enableTimer(); + } + + timer_callback getCallback(void) + { + return _callback; + } + + IRQn_Type getTimerIRQn(void) + { + return _timer_IRQ; + } +}; // class NRF52TimerInterrupt + +// Timer 0 is used by the soft device but Timer 1, 2, 3 and 4 are available +extern "C" void TIMER1_IRQHandler(void) +{ + if (nRF52Timers[1]) + { + nRF52Timers[1]->detachInterrupt(); + + (*(nRF52Timers[1]->getCallback()))(); + + nRF52Timers[1]->enableTimer(); + } +} + +extern "C" void TIMER2_IRQHandler(void) +{ + if (nRF52Timers[2]) + { + nRF52Timers[2]->detachInterrupt(); + + (*(nRF52Timers[2]->getCallback()))(); + + nRF52Timers[2]->enableTimer(); + } +} + +extern "C" void TIMER3_IRQHandler(void) +{ + if (nRF52Timers[3]) + { + nRF52Timers[3]->detachInterrupt(); + + (*(nRF52Timers[3]->getCallback()))(); + + nRF52Timers[3]->enableTimer(); + } +} + +extern "C" void TIMER4_IRQHandler(void) +{ + if (nRF52Timers[4]) + { + nRF52Timers[4]->detachInterrupt(); + + (*(nRF52Timers[4]->getCallback()))(); + + nRF52Timers[4]->enableTimer(); + } +} diff --git a/src/NRF52_ISR_Timer-Impl.h b/src/NRF52_ISR_Timer-Impl.h new file mode 100644 index 0000000..ab331d6 --- /dev/null +++ b/src/NRF52_ISR_Timer-Impl.h @@ -0,0 +1,337 @@ +/**************************************************************************************************************************** + NRF52_ISR_Timer-Impl.h + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ + +#pragma once + +//#include "NRF52_ISR_Timer.h" +#include + +NRF52_ISR_Timer::NRF52_ISR_Timer() + : numTimers (-1) +{ +} + +void NRF52_ISR_Timer::init() +{ + unsigned long current_millis = millis(); //elapsed(); + + for (int i = 0; i < MAX_TIMERS; i++) + { + memset((void*) &timer[i], 0, sizeof (timer_t)); + timer[i].prev_millis = current_millis; + } + + numTimers = 0; +} + +void NRF52_ISR_Timer::run() +{ + int i; + unsigned long current_millis; + + // get current time + current_millis = millis(); //elapsed(); + + for (i = 0; i < MAX_TIMERS; i++) + { + + timer[i].toBeCalled = DEFCALL_DONTRUN; + + // no callback == no timer, i.e. jump over empty slots + if (timer[i].callback != NULL) + { + + // is it time to process this timer ? + // see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592 + + if ((current_millis - timer[i].prev_millis) >= timer[i].delay) + { + unsigned long skipTimes = (current_millis - timer[i].prev_millis) / timer[i].delay; + + // update time + timer[i].prev_millis += timer[i].delay * skipTimes; + + // check if the timer callback has to be executed + if (timer[i].enabled) + { + + // "run forever" timers must always be executed + if (timer[i].maxNumRuns == RUN_FOREVER) + { + timer[i].toBeCalled = DEFCALL_RUNONLY; + } + // other timers get executed the specified number of times + else if (timer[i].numRuns < timer[i].maxNumRuns) + { + timer[i].toBeCalled = DEFCALL_RUNONLY; + timer[i].numRuns++; + + // after the last run, delete the timer + if (timer[i].numRuns >= timer[i].maxNumRuns) + { + timer[i].toBeCalled = DEFCALL_RUNANDDEL; + } + } + } + } + } + } + + for (i = 0; i < MAX_TIMERS; i++) + { + if (timer[i].toBeCalled == DEFCALL_DONTRUN) + continue; + + if (timer[i].hasParam) + (*(timer_callback_p)timer[i].callback)(timer[i].param); + else + (*(timer_callback)timer[i].callback)(); + + if (timer[i].toBeCalled == DEFCALL_RUNANDDEL) + deleteTimer(i); + } +} + + +// find the first available slot +// return -1 if none found +int NRF52_ISR_Timer::findFirstFreeSlot() +{ + // all slots are used + if (numTimers >= MAX_TIMERS) + { + return -1; + } + + // return the first slot with no callback (i.e. free) + for (int i = 0; i < MAX_TIMERS; i++) + { + if (timer[i].callback == NULL) + { + return i; + } + } + + // no free slots found + return -1; +} + + +int NRF52_ISR_Timer::setupTimer(unsigned long d, void* f, void* p, bool h, unsigned n) +{ + int freeTimer; + + if (numTimers < 0) + { + init(); + } + + freeTimer = findFirstFreeSlot(); + if (freeTimer < 0) + { + return -1; + } + + if (f == NULL) + { + return -1; + } + + timer[freeTimer].delay = d; + timer[freeTimer].callback = f; + timer[freeTimer].param = p; + timer[freeTimer].hasParam = h; + timer[freeTimer].maxNumRuns = n; + timer[freeTimer].enabled = true; + timer[freeTimer].prev_millis = millis(); + + numTimers++; + + return freeTimer; +} + + +int NRF52_ISR_Timer::setTimer(unsigned long d, timer_callback f, unsigned n) +{ + return setupTimer(d, (void *)f, NULL, false, n); +} + +int NRF52_ISR_Timer::setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n) +{ + return setupTimer(d, (void *)f, p, true, n); +} + +int NRF52_ISR_Timer::setInterval(unsigned long d, timer_callback f) +{ + return setupTimer(d, (void *)f, NULL, false, RUN_FOREVER); +} + +int NRF52_ISR_Timer::setInterval(unsigned long d, timer_callback_p f, void* p) +{ + return setupTimer(d, (void *)f, p, true, RUN_FOREVER); +} + +int NRF52_ISR_Timer::setTimeout(unsigned long d, timer_callback f) +{ + return setupTimer(d, (void *)f, NULL, false, RUN_ONCE); +} + +int NRF52_ISR_Timer::setTimeout(unsigned long d, timer_callback_p f, void* p) +{ + return setupTimer(d, (void *)f, p, true, RUN_ONCE); +} + +bool NRF52_ISR_Timer::changeInterval(unsigned numTimer, unsigned long d) +{ + if (numTimer >= MAX_TIMERS) + { + return false; + } + + // Updates interval of existing specified timer + if (timer[numTimer].callback != NULL) + { + timer[numTimer].delay = d; + timer[numTimer].prev_millis = millis(); + + return true; + } + + // false return for non-used numTimer, no callback + return false; +} + +void NRF52_ISR_Timer::deleteTimer(unsigned timerId) +{ + if (timerId >= MAX_TIMERS) + { + return; + } + + // nothing to delete if no timers are in use + if (numTimers == 0) + { + return; + } + + // don't decrease the number of timers if the specified slot is already empty + if (timer[timerId].callback != NULL) + { + memset((void*) &timer[timerId], 0, sizeof (timer_t)); + timer[timerId].prev_millis = millis(); + + // update number of timers + numTimers--; + } +} + +// function contributed by code@rowansimms.com +void NRF52_ISR_Timer::restartTimer(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return; + } + + timer[numTimer].prev_millis = millis(); +} + + +bool NRF52_ISR_Timer::isEnabled(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return false; + } + + return timer[numTimer].enabled; +} + + +void NRF52_ISR_Timer::enable(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return; + } + + timer[numTimer].enabled = true; +} + + +void NRF52_ISR_Timer::disable(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return; + } + + timer[numTimer].enabled = false; +} + +void NRF52_ISR_Timer::enableAll() +{ + // Enable all timers with a callback assigned (used) + + for (int i = 0; i < MAX_TIMERS; i++) + { + if (timer[i].callback != NULL && timer[i].numRuns == RUN_FOREVER) + { + timer[i].enabled = true; + } + } +} + +void NRF52_ISR_Timer::disableAll() +{ + // Disable all timers with a callback assigned (used) + + for (int i = 0; i < MAX_TIMERS; i++) + { + if (timer[i].callback != NULL && timer[i].numRuns == RUN_FOREVER) + { + timer[i].enabled = false; + } + } +} + +void NRF52_ISR_Timer::toggle(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return; + } + + timer[numTimer].enabled = !timer[numTimer].enabled; +} + + +unsigned NRF52_ISR_Timer::getNumTimers() +{ + return numTimers; +} diff --git a/src/NRF52_ISR_Timer.h b/src/NRF52_ISR_Timer.h new file mode 100644 index 0000000..50f687e --- /dev/null +++ b/src/NRF52_ISR_Timer.h @@ -0,0 +1,173 @@ +/**************************************************************************************************************************** + NRF52_ISR_Timer.h + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ + +#pragma once + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +#include + +#include + +#if defined(ARDUINO) + #if ARDUINO >= 100 + #include + #else + #include + #endif +#endif + +#define NRF52_ISR_Timer NRF52_ISRTimer + +typedef void (*timer_callback)(void); +typedef void (*timer_callback_p)(void *); + +class NRF52_ISR_Timer +{ + + public: + // maximum number of timers +#define MAX_TIMERS 16 +#define RUN_FOREVER 0 +#define RUN_ONCE 1 + + // constructor + NRF52_ISR_Timer(); + + void init(); + + // this function must be called inside loop() + void run(); + + // Timer will call function 'f' every 'd' milliseconds forever + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setInterval(unsigned long d, timer_callback f); + + // Timer will call function 'f' with parameter 'p' every 'd' milliseconds forever + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setInterval(unsigned long d, timer_callback_p f, void* p); + + // Timer will call function 'f' after 'd' milliseconds one time + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimeout(unsigned long d, timer_callback f); + + // Timer will call function 'f' with parameter 'p' after 'd' milliseconds one time + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimeout(unsigned long d, timer_callback_p f, void* p); + + // Timer will call function 'f' every 'd' milliseconds 'n' times + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimer(unsigned long d, timer_callback f, unsigned n); + + // Timer will call function 'f' with parameter 'p' every 'd' milliseconds 'n' times + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n); + + // updates interval of the specified timer + bool changeInterval(unsigned numTimer, unsigned long d); + + // destroy the specified timer + void deleteTimer(unsigned numTimer); + + // restart the specified timer + void restartTimer(unsigned numTimer); + + // returns true if the specified timer is enabled + bool isEnabled(unsigned numTimer); + + // enables the specified timer + void enable(unsigned numTimer); + + // disables the specified timer + void disable(unsigned numTimer); + + // enables all timers + void enableAll(); + + // disables all timers + void disableAll(); + + // enables the specified timer if it's currently disabled, and vice-versa + void toggle(unsigned numTimer); + + // returns the number of used timers + unsigned getNumTimers(); + + // returns the number of available timers + unsigned getNumAvailableTimers() + { + return MAX_TIMERS - numTimers; + }; + + private: + // deferred call constants +#define DEFCALL_DONTRUN 0 // don't call the callback function +#define DEFCALL_RUNONLY 1 // call the callback function but don't delete the timer +#define DEFCALL_RUNANDDEL 2 // call the callback function and delete the timer + + // low level function to initialize and enable a new timer + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setupTimer(unsigned long d, void* f, void* p, bool h, unsigned n); + + // find the first available slot + int findFirstFreeSlot(); + + typedef struct + { + unsigned long prev_millis; // value returned by the millis() function in the previous run() call + void* callback; // pointer to the callback function + void* param; // function parameter + bool hasParam; // true if callback takes a parameter + unsigned long delay; // delay value + unsigned maxNumRuns; // number of runs to be executed + unsigned numRuns; // number of executed runs + bool enabled; // true if enabled + unsigned toBeCalled; // deferred function call (sort of) - N.B.: only used in run() + } timer_t; + + volatile timer_t timer[MAX_TIMERS]; + + // actual number of timers in use (-1 means uninitialized) + volatile int numTimers; +}; + + +#include "NRF52_ISR_Timer-Impl.h" + diff --git a/src_cpp/NRF52TimerInterrupt.h b/src_cpp/NRF52TimerInterrupt.h new file mode 100644 index 0000000..8308862 --- /dev/null +++ b/src_cpp/NRF52TimerInterrupt.h @@ -0,0 +1,390 @@ +/**************************************************************************************************************************** + NRF52TimerInterrupt.h + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ +/* + nRF52 has 5 Hardware TIMERs: NRF_TIMER0-NRF_TIMER4 + NRF_TIMER0 is used by the soft device, NRF_TIMER1-NRF_TIMER4 are available + + Defined in file ./adafruit/hardware/nrf52/0.21.0/cores/nRF5/nordic/nrfx/mdk/nrf52.h + + #define NRF_TIMER0_BASE 0x40008000UL + #define NRF_TIMER1_BASE 0x40009000UL + #define NRF_TIMER2_BASE 0x4000A000UL + #define NRF_TIMER3_BASE 0x4001A000UL + #define NRF_TIMER4_BASE 0x4001B000UL + ... + #define NRF_TIMER0 ((NRF_TIMER_Type*) NRF_TIMER0_BASE) + #define NRF_TIMER1 ((NRF_TIMER_Type*) NRF_TIMER1_BASE) + #define NRF_TIMER2 ((NRF_TIMER_Type*) NRF_TIMER2_BASE) + #define NRF_TIMER3 ((NRF_TIMER_Type*) NRF_TIMER3_BASE) + #define NRF_TIMER4 ((NRF_TIMER_Type*) NRF_TIMER4_BASE) + + =============================================================================== + + Defined in ./adafruit/hardware/nrf52/0.21.0/cores/nRF5/nordic/nrfx/hal/nrf_timer.h + + Timer prescalers + typedef enum + { + NRF_TIMER_FREQ_16MHz = 0, ///< Timer frequency 16 MHz. + NRF_TIMER_FREQ_8MHz, ///< Timer frequency 8 MHz. + NRF_TIMER_FREQ_4MHz, ///< Timer frequency 4 MHz. + NRF_TIMER_FREQ_2MHz, ///< Timer frequency 2 MHz. + NRF_TIMER_FREQ_1MHz, ///< Timer frequency 1 MHz. + NRF_TIMER_FREQ_500kHz, ///< Timer frequency 500 kHz. + NRF_TIMER_FREQ_250kHz, ///< Timer frequency 250 kHz. + NRF_TIMER_FREQ_125kHz, ///< Timer frequency 125 kHz. + NRF_TIMER_FREQ_62500Hz, ///< Timer frequency 62500 Hz. + NRF_TIMER_FREQ_31250Hz ///< Timer frequency 31250 Hz. + } nrf_timer_frequency_t; + +*/ +#pragma once + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +#include +#include "nrf_timer.h" + +#define NRF52_TIMER_INTERRUPT_VERSION "1.0.0" + +#ifndef NRF52_TIMER_INTERRUPT_DEBUG + #define NRF52_TIMER_INTERRUPT_DEBUG 0 +#endif + +class NRF52TimerInterrupt; + +typedef NRF52TimerInterrupt NRF52Timer; + +typedef void (*timer_callback) (void); + +typedef enum +{ + NRF_TIMER_0 = 0, + NRF_TIMER_1 = 1, + NRF_TIMER_2 = 2, + NRF_TIMER_3 = 3, + NRF_TIMER_4 = 4, + NRF_MAX_TIMER +} NRF52TimerNumber; + +const char* NRF52TimerName[NRF_MAX_TIMER] = +{ + "NRF_TIMER0-DON'T_USE_THIS", + "NRF_TIMER1", + "NRF_TIMER2", + "NRF_TIMER3", + "NRF_TIMER4", +}; + +/* +typedef enum +{ + NRF_TIMER_CC_CHANNEL0 = 0, ///< Timer capture/compare channel 0. + NRF_TIMER_CC_CHANNEL1, ///< Timer capture/compare channel 1. + NRF_TIMER_CC_CHANNEL2, ///< Timer capture/compare channel 2. + NRF_TIMER_CC_CHANNEL3, ///< Timer capture/compare channel 3. +#ifdef NRF52 + NRF_TIMER_CC_CHANNEL4, ///< Timer capture/compare channel 4. + NRF_TIMER_CC_CHANNEL5, ///< Timer capture/compare channel 5. +#endif +} nrf_timer_cc_channel_t; +*/ + +class NRF52TimerInterrupt; + +NRF_TIMER_Type* nrf_timers [NRF_MAX_TIMER] = { NRF_TIMER0, NRF_TIMER1, NRF_TIMER2, NRF_TIMER3, NRF_TIMER4 }; + +IRQn_Type nrf_timers_irq[NRF_MAX_TIMER] = { TIMER0_IRQn, TIMER1_IRQn, TIMER2_IRQn, TIMER3_IRQn, TIMER4_IRQn }; + +NRF52TimerInterrupt* nRF52Timers [NRF_MAX_TIMER] = { NULL, NULL, NULL, NULL, NULL }; + + +class NRF52TimerInterrupt +{ + private: + uint8_t _timer = NRF_TIMER_1; + + NRF_TIMER_Type* nrf_timer = NRF_TIMER1; + nrf_timer_cc_channel_t cc_channel = NRF_TIMER_CC_CHANNEL0; + + IRQn_Type _timer_IRQ; + + timer_callback _callback; // pointer to the callback function + + // NRF_TIMER_FREQ_16MHz,NRF_TIMER_FREQ_8MHz,...,NRF_TIMER_FREQ_31250Hz + nrf_timer_frequency_t _frequency_t = NRF_TIMER_FREQ_1MHz; + float _frequency; // Timer frequency + uint32_t _timerCount; // count to activate timer + + public: + + NRF52TimerInterrupt(uint8_t timer = NRF_TIMER_1) + { + // KH, force to use NRF_TIMER1 if accidentally select already used NRF_TIMER0 + // To store to know which to delete in destructor + if (timer == NRF_TIMER_0) + _timer = NRF_TIMER_1; + else + _timer = timer; + + nrf_timer = nrf_timers[_timer]; + + _timer_IRQ = nrf_timers_irq[_timer]; + + // Update to use in TIMERx_IRQHandler + nRF52Timers[_timer] = this; + + _callback = NULL; + + // Timer mode with 32bit width + nrf_timer_bit_width_set(nrf_timer, NRF_TIMER_BIT_WIDTH_32); + nrf_timer_mode_set(nrf_timer, NRF_TIMER_MODE_TIMER); + + // KH, just 1MHz is enough. 16MHz can have better accuracy, but shorter time range. + nrf_timer_frequency_set(nrf_timer, _frequency_t); + + switch (_frequency_t) + { + case NRF_TIMER_FREQ_16MHz: + _frequency = 16000000.0f; + + break; + case NRF_TIMER_FREQ_8MHz: + _frequency = 8000000.0f; + + break; + case NRF_TIMER_FREQ_4MHz: + _frequency = 4000000.0f; + + break; + case NRF_TIMER_FREQ_2MHz: + _frequency = 2000000.0f; + + break; + case NRF_TIMER_FREQ_1MHz: + _frequency = 1000000.0f; + + break; + default: + _frequency = 1000000.0f; + break; + } + }; + + ~NRF52TimerInterrupt() + { + nRF52Timers[_timer] = NULL; + } + + // frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely + // No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c + bool setFrequency(float frequency, timer_callback callback) + { + // This function will be called when time out interrupt will occur + if (callback) + { + _callback = callback; + } + else + { + Serial.println("NRF52TimerInterrupt: ERROR: NULL callback function pointer."); + return false; + } + + if ( (frequency <= 0) || (frequency > _frequency / 10.0f) ) + { + Serial.println("NRF52TimerInterrupt: ERROR: Negative or Too high frequency. Must be <= " + String(_frequency/10.0f)); + return false; + } + + // select timer frequency is 1MHz for better accuracy. We don't use 16-bit prescaler for now. + // Will use later if very low frequency is needed. + _timerCount = (uint32_t) _frequency / frequency; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + Serial.println("NRF52TimerInterrupt: F_CPU (MHz) = " + String(F_CPU/1000000) + ", Timer = " + NRF52TimerName[_timer] ); + Serial.println("NRF52TimerInterrupt: _fre = " + String(_frequency) + ", _count = " + String((uint32_t) (_timerCount))); +#endif + + // Start if not already running (and reset?) + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_START); + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_CLEAR); + + // Clear and enable compare interrupt + nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel); + nrf_timer_int_enable(nrf_timer, channel_mask); + + NVIC_EnableIRQ(_timer_IRQ); + + //nrf_timer_cc_write(nrf_timer, cc_channel, _timerCount); + // New for Adafruit nRF52 core 0.21.0 + nrf_timer_cc_set(nrf_timer, cc_channel, _timerCount); + + return true; + } + + // interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely + // No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c + bool setInterval(unsigned long interval, timer_callback callback) + { + return setFrequency((float) (1000000.0f / interval), callback); + } + + bool attachInterrupt(float frequency, timer_callback callback) + { + return setFrequency(frequency, callback); + } + + // interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely + // No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c + bool attachInterruptInterval(unsigned long interval, timer_callback callback) + { + return setFrequency( (float) ( 1000000.0f / interval), callback); + } + + void detachInterrupt(void) + { + NVIC_DisableIRQ(_timer_IRQ); + + // Stop timer + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_STOP); + + // Disable timer compare interrupt + nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel); + nrf_timer_int_disable(nrf_timer, channel_mask); + + // Clear event + nrf_timer_event_t event = nrf_timer_compare_event_get(channel_mask); + nrf_timer_event_clear(nrf_timer, event); + } + + void disableTimer(void) + { + detachInterrupt(); + } + + // Duration (in milliseconds). Duration = 0 or not specified => run indefinitely + void reattachInterrupt() + { + setFrequency(_frequency, _callback); + } + + // Duration (in milliseconds). Duration = 0 or not specified => run indefinitely + void enableTimer(void) + { + // Start if not already running (and reset?) + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_START); + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_CLEAR); + + // Clear and enable compare interrupt + nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel); + nrf_timer_int_enable(nrf_timer, channel_mask); + + NVIC_EnableIRQ(_timer_IRQ); + + //nrf_timer_cc_write(nrf_timer, cc_channel, _timerCount); + // New for Adafruit nRF52 core 0.21.0 + nrf_timer_cc_set(nrf_timer, cc_channel, _timerCount); + } + + // Just stop clock source, clear the count + void stopTimer(void) + { + disableTimer(); + } + + // Just reconnect clock source, start current count from 0 + void restartTimer(void) + { + enableTimer(); + } + + timer_callback getCallback(void) + { + return _callback; + } + + IRQn_Type getTimerIRQn(void) + { + return _timer_IRQ; + } +}; // class NRF52TimerInterrupt + +// Timer 0 is used by the soft device but Timer 1, 2, 3 and 4 are available +extern "C" void TIMER1_IRQHandler(void) +{ + if (nRF52Timers[1]) + { + nRF52Timers[1]->detachInterrupt(); + + (*(nRF52Timers[1]->getCallback()))(); + + nRF52Timers[1]->enableTimer(); + } +} + +extern "C" void TIMER2_IRQHandler(void) +{ + if (nRF52Timers[2]) + { + nRF52Timers[2]->detachInterrupt(); + + (*(nRF52Timers[2]->getCallback()))(); + + nRF52Timers[2]->enableTimer(); + } +} + +extern "C" void TIMER3_IRQHandler(void) +{ + if (nRF52Timers[3]) + { + nRF52Timers[3]->detachInterrupt(); + + (*(nRF52Timers[3]->getCallback()))(); + + nRF52Timers[3]->enableTimer(); + } +} + +extern "C" void TIMER4_IRQHandler(void) +{ + if (nRF52Timers[4]) + { + nRF52Timers[4]->detachInterrupt(); + + (*(nRF52Timers[4]->getCallback()))(); + + nRF52Timers[4]->enableTimer(); + } +} diff --git a/src_cpp/NRF52_ISR_Timer.cpp b/src_cpp/NRF52_ISR_Timer.cpp new file mode 100644 index 0000000..1dc6c50 --- /dev/null +++ b/src_cpp/NRF52_ISR_Timer.cpp @@ -0,0 +1,335 @@ +/**************************************************************************************************************************** + NRF52_ISR_Timer.cpp + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ + +#include "NRF52_ISR_Timer.h" +#include + +NRF52_ISR_Timer::NRF52_ISR_Timer() + : numTimers (-1) +{ +} + +void NRF52_ISR_Timer::init() +{ + unsigned long current_millis = millis(); //elapsed(); + + for (int i = 0; i < MAX_TIMERS; i++) + { + memset((void*) &timer[i], 0, sizeof (timer_t)); + timer[i].prev_millis = current_millis; + } + + numTimers = 0; +} + +void NRF52_ISR_Timer::run() +{ + int i; + unsigned long current_millis; + + // get current time + current_millis = millis(); //elapsed(); + + for (i = 0; i < MAX_TIMERS; i++) + { + + timer[i].toBeCalled = DEFCALL_DONTRUN; + + // no callback == no timer, i.e. jump over empty slots + if (timer[i].callback != NULL) + { + + // is it time to process this timer ? + // see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592 + + if ((current_millis - timer[i].prev_millis) >= timer[i].delay) + { + unsigned long skipTimes = (current_millis - timer[i].prev_millis) / timer[i].delay; + + // update time + timer[i].prev_millis += timer[i].delay * skipTimes; + + // check if the timer callback has to be executed + if (timer[i].enabled) + { + + // "run forever" timers must always be executed + if (timer[i].maxNumRuns == RUN_FOREVER) + { + timer[i].toBeCalled = DEFCALL_RUNONLY; + } + // other timers get executed the specified number of times + else if (timer[i].numRuns < timer[i].maxNumRuns) + { + timer[i].toBeCalled = DEFCALL_RUNONLY; + timer[i].numRuns++; + + // after the last run, delete the timer + if (timer[i].numRuns >= timer[i].maxNumRuns) + { + timer[i].toBeCalled = DEFCALL_RUNANDDEL; + } + } + } + } + } + } + + for (i = 0; i < MAX_TIMERS; i++) + { + if (timer[i].toBeCalled == DEFCALL_DONTRUN) + continue; + + if (timer[i].hasParam) + (*(timer_callback_p)timer[i].callback)(timer[i].param); + else + (*(timer_callback)timer[i].callback)(); + + if (timer[i].toBeCalled == DEFCALL_RUNANDDEL) + deleteTimer(i); + } +} + + +// find the first available slot +// return -1 if none found +int NRF52_ISR_Timer::findFirstFreeSlot() +{ + // all slots are used + if (numTimers >= MAX_TIMERS) + { + return -1; + } + + // return the first slot with no callback (i.e. free) + for (int i = 0; i < MAX_TIMERS; i++) + { + if (timer[i].callback == NULL) + { + return i; + } + } + + // no free slots found + return -1; +} + + +int NRF52_ISR_Timer::setupTimer(unsigned long d, void* f, void* p, bool h, unsigned n) +{ + int freeTimer; + + if (numTimers < 0) + { + init(); + } + + freeTimer = findFirstFreeSlot(); + if (freeTimer < 0) + { + return -1; + } + + if (f == NULL) + { + return -1; + } + + timer[freeTimer].delay = d; + timer[freeTimer].callback = f; + timer[freeTimer].param = p; + timer[freeTimer].hasParam = h; + timer[freeTimer].maxNumRuns = n; + timer[freeTimer].enabled = true; + timer[freeTimer].prev_millis = millis(); + + numTimers++; + + return freeTimer; +} + + +int NRF52_ISR_Timer::setTimer(unsigned long d, timer_callback f, unsigned n) +{ + return setupTimer(d, (void *)f, NULL, false, n); +} + +int NRF52_ISR_Timer::setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n) +{ + return setupTimer(d, (void *)f, p, true, n); +} + +int NRF52_ISR_Timer::setInterval(unsigned long d, timer_callback f) +{ + return setupTimer(d, (void *)f, NULL, false, RUN_FOREVER); +} + +int NRF52_ISR_Timer::setInterval(unsigned long d, timer_callback_p f, void* p) +{ + return setupTimer(d, (void *)f, p, true, RUN_FOREVER); +} + +int NRF52_ISR_Timer::setTimeout(unsigned long d, timer_callback f) +{ + return setupTimer(d, (void *)f, NULL, false, RUN_ONCE); +} + +int NRF52_ISR_Timer::setTimeout(unsigned long d, timer_callback_p f, void* p) +{ + return setupTimer(d, (void *)f, p, true, RUN_ONCE); +} + +bool NRF52_ISR_Timer::changeInterval(unsigned numTimer, unsigned long d) +{ + if (numTimer >= MAX_TIMERS) + { + return false; + } + + // Updates interval of existing specified timer + if (timer[numTimer].callback != NULL) + { + timer[numTimer].delay = d; + timer[numTimer].prev_millis = millis(); + + return true; + } + + // false return for non-used numTimer, no callback + return false; +} + +void NRF52_ISR_Timer::deleteTimer(unsigned timerId) +{ + if (timerId >= MAX_TIMERS) + { + return; + } + + // nothing to delete if no timers are in use + if (numTimers == 0) + { + return; + } + + // don't decrease the number of timers if the specified slot is already empty + if (timer[timerId].callback != NULL) + { + memset((void*) &timer[timerId], 0, sizeof (timer_t)); + timer[timerId].prev_millis = millis(); + + // update number of timers + numTimers--; + } +} + +// function contributed by code@rowansimms.com +void NRF52_ISR_Timer::restartTimer(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return; + } + + timer[numTimer].prev_millis = millis(); +} + + +bool NRF52_ISR_Timer::isEnabled(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return false; + } + + return timer[numTimer].enabled; +} + + +void NRF52_ISR_Timer::enable(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return; + } + + timer[numTimer].enabled = true; +} + + +void NRF52_ISR_Timer::disable(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return; + } + + timer[numTimer].enabled = false; +} + +void NRF52_ISR_Timer::enableAll() +{ + // Enable all timers with a callback assigned (used) + + for (int i = 0; i < MAX_TIMERS; i++) + { + if (timer[i].callback != NULL && timer[i].numRuns == RUN_FOREVER) + { + timer[i].enabled = true; + } + } +} + +void NRF52_ISR_Timer::disableAll() +{ + // Disable all timers with a callback assigned (used) + + for (int i = 0; i < MAX_TIMERS; i++) + { + if (timer[i].callback != NULL && timer[i].numRuns == RUN_FOREVER) + { + timer[i].enabled = false; + } + } +} + +void NRF52_ISR_Timer::toggle(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return; + } + + timer[numTimer].enabled = !timer[numTimer].enabled; +} + + +unsigned NRF52_ISR_Timer::getNumTimers() +{ + return numTimers; +} diff --git a/src_cpp/NRF52_ISR_Timer.h b/src_cpp/NRF52_ISR_Timer.h new file mode 100644 index 0000000..ab331d2 --- /dev/null +++ b/src_cpp/NRF52_ISR_Timer.h @@ -0,0 +1,169 @@ +/**************************************************************************************************************************** + NRF52_ISR_Timer.h + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ + +#pragma once + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +#include + +#include + +#if defined(ARDUINO) + #if ARDUINO >= 100 + #include + #else + #include + #endif +#endif + +#define NRF52_ISR_Timer NRF52_ISRTimer + +typedef void (*timer_callback)(void); +typedef void (*timer_callback_p)(void *); + +class NRF52_ISR_Timer +{ + + public: + // maximum number of timers +#define MAX_TIMERS 16 +#define RUN_FOREVER 0 +#define RUN_ONCE 1 + + // constructor + NRF52_ISR_Timer(); + + void init(); + + // this function must be called inside loop() + void run(); + + // Timer will call function 'f' every 'd' milliseconds forever + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setInterval(unsigned long d, timer_callback f); + + // Timer will call function 'f' with parameter 'p' every 'd' milliseconds forever + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setInterval(unsigned long d, timer_callback_p f, void* p); + + // Timer will call function 'f' after 'd' milliseconds one time + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimeout(unsigned long d, timer_callback f); + + // Timer will call function 'f' with parameter 'p' after 'd' milliseconds one time + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimeout(unsigned long d, timer_callback_p f, void* p); + + // Timer will call function 'f' every 'd' milliseconds 'n' times + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimer(unsigned long d, timer_callback f, unsigned n); + + // Timer will call function 'f' with parameter 'p' every 'd' milliseconds 'n' times + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n); + + // updates interval of the specified timer + bool changeInterval(unsigned numTimer, unsigned long d); + + // destroy the specified timer + void deleteTimer(unsigned numTimer); + + // restart the specified timer + void restartTimer(unsigned numTimer); + + // returns true if the specified timer is enabled + bool isEnabled(unsigned numTimer); + + // enables the specified timer + void enable(unsigned numTimer); + + // disables the specified timer + void disable(unsigned numTimer); + + // enables all timers + void enableAll(); + + // disables all timers + void disableAll(); + + // enables the specified timer if it's currently disabled, and vice-versa + void toggle(unsigned numTimer); + + // returns the number of used timers + unsigned getNumTimers(); + + // returns the number of available timers + unsigned getNumAvailableTimers() + { + return MAX_TIMERS - numTimers; + }; + + private: + // deferred call constants +#define DEFCALL_DONTRUN 0 // don't call the callback function +#define DEFCALL_RUNONLY 1 // call the callback function but don't delete the timer +#define DEFCALL_RUNANDDEL 2 // call the callback function and delete the timer + + // low level function to initialize and enable a new timer + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setupTimer(unsigned long d, void* f, void* p, bool h, unsigned n); + + // find the first available slot + int findFirstFreeSlot(); + + typedef struct + { + unsigned long prev_millis; // value returned by the millis() function in the previous run() call + void* callback; // pointer to the callback function + void* param; // function parameter + bool hasParam; // true if callback takes a parameter + unsigned long delay; // delay value + unsigned maxNumRuns; // number of runs to be executed + unsigned numRuns; // number of executed runs + bool enabled; // true if enabled + unsigned toBeCalled; // deferred function call (sort of) - N.B.: only used in run() + } timer_t; + + volatile timer_t timer[MAX_TIMERS]; + + // actual number of timers in use (-1 means uninitialized) + volatile int numTimers; +}; diff --git a/src_h/NRF52TimerInterrupt.h b/src_h/NRF52TimerInterrupt.h new file mode 100644 index 0000000..8308862 --- /dev/null +++ b/src_h/NRF52TimerInterrupt.h @@ -0,0 +1,390 @@ +/**************************************************************************************************************************** + NRF52TimerInterrupt.h + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ +/* + nRF52 has 5 Hardware TIMERs: NRF_TIMER0-NRF_TIMER4 + NRF_TIMER0 is used by the soft device, NRF_TIMER1-NRF_TIMER4 are available + + Defined in file ./adafruit/hardware/nrf52/0.21.0/cores/nRF5/nordic/nrfx/mdk/nrf52.h + + #define NRF_TIMER0_BASE 0x40008000UL + #define NRF_TIMER1_BASE 0x40009000UL + #define NRF_TIMER2_BASE 0x4000A000UL + #define NRF_TIMER3_BASE 0x4001A000UL + #define NRF_TIMER4_BASE 0x4001B000UL + ... + #define NRF_TIMER0 ((NRF_TIMER_Type*) NRF_TIMER0_BASE) + #define NRF_TIMER1 ((NRF_TIMER_Type*) NRF_TIMER1_BASE) + #define NRF_TIMER2 ((NRF_TIMER_Type*) NRF_TIMER2_BASE) + #define NRF_TIMER3 ((NRF_TIMER_Type*) NRF_TIMER3_BASE) + #define NRF_TIMER4 ((NRF_TIMER_Type*) NRF_TIMER4_BASE) + + =============================================================================== + + Defined in ./adafruit/hardware/nrf52/0.21.0/cores/nRF5/nordic/nrfx/hal/nrf_timer.h + + Timer prescalers + typedef enum + { + NRF_TIMER_FREQ_16MHz = 0, ///< Timer frequency 16 MHz. + NRF_TIMER_FREQ_8MHz, ///< Timer frequency 8 MHz. + NRF_TIMER_FREQ_4MHz, ///< Timer frequency 4 MHz. + NRF_TIMER_FREQ_2MHz, ///< Timer frequency 2 MHz. + NRF_TIMER_FREQ_1MHz, ///< Timer frequency 1 MHz. + NRF_TIMER_FREQ_500kHz, ///< Timer frequency 500 kHz. + NRF_TIMER_FREQ_250kHz, ///< Timer frequency 250 kHz. + NRF_TIMER_FREQ_125kHz, ///< Timer frequency 125 kHz. + NRF_TIMER_FREQ_62500Hz, ///< Timer frequency 62500 Hz. + NRF_TIMER_FREQ_31250Hz ///< Timer frequency 31250 Hz. + } nrf_timer_frequency_t; + +*/ +#pragma once + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +#include +#include "nrf_timer.h" + +#define NRF52_TIMER_INTERRUPT_VERSION "1.0.0" + +#ifndef NRF52_TIMER_INTERRUPT_DEBUG + #define NRF52_TIMER_INTERRUPT_DEBUG 0 +#endif + +class NRF52TimerInterrupt; + +typedef NRF52TimerInterrupt NRF52Timer; + +typedef void (*timer_callback) (void); + +typedef enum +{ + NRF_TIMER_0 = 0, + NRF_TIMER_1 = 1, + NRF_TIMER_2 = 2, + NRF_TIMER_3 = 3, + NRF_TIMER_4 = 4, + NRF_MAX_TIMER +} NRF52TimerNumber; + +const char* NRF52TimerName[NRF_MAX_TIMER] = +{ + "NRF_TIMER0-DON'T_USE_THIS", + "NRF_TIMER1", + "NRF_TIMER2", + "NRF_TIMER3", + "NRF_TIMER4", +}; + +/* +typedef enum +{ + NRF_TIMER_CC_CHANNEL0 = 0, ///< Timer capture/compare channel 0. + NRF_TIMER_CC_CHANNEL1, ///< Timer capture/compare channel 1. + NRF_TIMER_CC_CHANNEL2, ///< Timer capture/compare channel 2. + NRF_TIMER_CC_CHANNEL3, ///< Timer capture/compare channel 3. +#ifdef NRF52 + NRF_TIMER_CC_CHANNEL4, ///< Timer capture/compare channel 4. + NRF_TIMER_CC_CHANNEL5, ///< Timer capture/compare channel 5. +#endif +} nrf_timer_cc_channel_t; +*/ + +class NRF52TimerInterrupt; + +NRF_TIMER_Type* nrf_timers [NRF_MAX_TIMER] = { NRF_TIMER0, NRF_TIMER1, NRF_TIMER2, NRF_TIMER3, NRF_TIMER4 }; + +IRQn_Type nrf_timers_irq[NRF_MAX_TIMER] = { TIMER0_IRQn, TIMER1_IRQn, TIMER2_IRQn, TIMER3_IRQn, TIMER4_IRQn }; + +NRF52TimerInterrupt* nRF52Timers [NRF_MAX_TIMER] = { NULL, NULL, NULL, NULL, NULL }; + + +class NRF52TimerInterrupt +{ + private: + uint8_t _timer = NRF_TIMER_1; + + NRF_TIMER_Type* nrf_timer = NRF_TIMER1; + nrf_timer_cc_channel_t cc_channel = NRF_TIMER_CC_CHANNEL0; + + IRQn_Type _timer_IRQ; + + timer_callback _callback; // pointer to the callback function + + // NRF_TIMER_FREQ_16MHz,NRF_TIMER_FREQ_8MHz,...,NRF_TIMER_FREQ_31250Hz + nrf_timer_frequency_t _frequency_t = NRF_TIMER_FREQ_1MHz; + float _frequency; // Timer frequency + uint32_t _timerCount; // count to activate timer + + public: + + NRF52TimerInterrupt(uint8_t timer = NRF_TIMER_1) + { + // KH, force to use NRF_TIMER1 if accidentally select already used NRF_TIMER0 + // To store to know which to delete in destructor + if (timer == NRF_TIMER_0) + _timer = NRF_TIMER_1; + else + _timer = timer; + + nrf_timer = nrf_timers[_timer]; + + _timer_IRQ = nrf_timers_irq[_timer]; + + // Update to use in TIMERx_IRQHandler + nRF52Timers[_timer] = this; + + _callback = NULL; + + // Timer mode with 32bit width + nrf_timer_bit_width_set(nrf_timer, NRF_TIMER_BIT_WIDTH_32); + nrf_timer_mode_set(nrf_timer, NRF_TIMER_MODE_TIMER); + + // KH, just 1MHz is enough. 16MHz can have better accuracy, but shorter time range. + nrf_timer_frequency_set(nrf_timer, _frequency_t); + + switch (_frequency_t) + { + case NRF_TIMER_FREQ_16MHz: + _frequency = 16000000.0f; + + break; + case NRF_TIMER_FREQ_8MHz: + _frequency = 8000000.0f; + + break; + case NRF_TIMER_FREQ_4MHz: + _frequency = 4000000.0f; + + break; + case NRF_TIMER_FREQ_2MHz: + _frequency = 2000000.0f; + + break; + case NRF_TIMER_FREQ_1MHz: + _frequency = 1000000.0f; + + break; + default: + _frequency = 1000000.0f; + break; + } + }; + + ~NRF52TimerInterrupt() + { + nRF52Timers[_timer] = NULL; + } + + // frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely + // No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c + bool setFrequency(float frequency, timer_callback callback) + { + // This function will be called when time out interrupt will occur + if (callback) + { + _callback = callback; + } + else + { + Serial.println("NRF52TimerInterrupt: ERROR: NULL callback function pointer."); + return false; + } + + if ( (frequency <= 0) || (frequency > _frequency / 10.0f) ) + { + Serial.println("NRF52TimerInterrupt: ERROR: Negative or Too high frequency. Must be <= " + String(_frequency/10.0f)); + return false; + } + + // select timer frequency is 1MHz for better accuracy. We don't use 16-bit prescaler for now. + // Will use later if very low frequency is needed. + _timerCount = (uint32_t) _frequency / frequency; + +#if (NRF52_TIMER_INTERRUPT_DEBUG > 0) + Serial.println("NRF52TimerInterrupt: F_CPU (MHz) = " + String(F_CPU/1000000) + ", Timer = " + NRF52TimerName[_timer] ); + Serial.println("NRF52TimerInterrupt: _fre = " + String(_frequency) + ", _count = " + String((uint32_t) (_timerCount))); +#endif + + // Start if not already running (and reset?) + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_START); + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_CLEAR); + + // Clear and enable compare interrupt + nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel); + nrf_timer_int_enable(nrf_timer, channel_mask); + + NVIC_EnableIRQ(_timer_IRQ); + + //nrf_timer_cc_write(nrf_timer, cc_channel, _timerCount); + // New for Adafruit nRF52 core 0.21.0 + nrf_timer_cc_set(nrf_timer, cc_channel, _timerCount); + + return true; + } + + // interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely + // No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c + bool setInterval(unsigned long interval, timer_callback callback) + { + return setFrequency((float) (1000000.0f / interval), callback); + } + + bool attachInterrupt(float frequency, timer_callback callback) + { + return setFrequency(frequency, callback); + } + + // interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely + // No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c + bool attachInterruptInterval(unsigned long interval, timer_callback callback) + { + return setFrequency( (float) ( 1000000.0f / interval), callback); + } + + void detachInterrupt(void) + { + NVIC_DisableIRQ(_timer_IRQ); + + // Stop timer + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_STOP); + + // Disable timer compare interrupt + nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel); + nrf_timer_int_disable(nrf_timer, channel_mask); + + // Clear event + nrf_timer_event_t event = nrf_timer_compare_event_get(channel_mask); + nrf_timer_event_clear(nrf_timer, event); + } + + void disableTimer(void) + { + detachInterrupt(); + } + + // Duration (in milliseconds). Duration = 0 or not specified => run indefinitely + void reattachInterrupt() + { + setFrequency(_frequency, _callback); + } + + // Duration (in milliseconds). Duration = 0 or not specified => run indefinitely + void enableTimer(void) + { + // Start if not already running (and reset?) + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_START); + nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_CLEAR); + + // Clear and enable compare interrupt + nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel); + nrf_timer_int_enable(nrf_timer, channel_mask); + + NVIC_EnableIRQ(_timer_IRQ); + + //nrf_timer_cc_write(nrf_timer, cc_channel, _timerCount); + // New for Adafruit nRF52 core 0.21.0 + nrf_timer_cc_set(nrf_timer, cc_channel, _timerCount); + } + + // Just stop clock source, clear the count + void stopTimer(void) + { + disableTimer(); + } + + // Just reconnect clock source, start current count from 0 + void restartTimer(void) + { + enableTimer(); + } + + timer_callback getCallback(void) + { + return _callback; + } + + IRQn_Type getTimerIRQn(void) + { + return _timer_IRQ; + } +}; // class NRF52TimerInterrupt + +// Timer 0 is used by the soft device but Timer 1, 2, 3 and 4 are available +extern "C" void TIMER1_IRQHandler(void) +{ + if (nRF52Timers[1]) + { + nRF52Timers[1]->detachInterrupt(); + + (*(nRF52Timers[1]->getCallback()))(); + + nRF52Timers[1]->enableTimer(); + } +} + +extern "C" void TIMER2_IRQHandler(void) +{ + if (nRF52Timers[2]) + { + nRF52Timers[2]->detachInterrupt(); + + (*(nRF52Timers[2]->getCallback()))(); + + nRF52Timers[2]->enableTimer(); + } +} + +extern "C" void TIMER3_IRQHandler(void) +{ + if (nRF52Timers[3]) + { + nRF52Timers[3]->detachInterrupt(); + + (*(nRF52Timers[3]->getCallback()))(); + + nRF52Timers[3]->enableTimer(); + } +} + +extern "C" void TIMER4_IRQHandler(void) +{ + if (nRF52Timers[4]) + { + nRF52Timers[4]->detachInterrupt(); + + (*(nRF52Timers[4]->getCallback()))(); + + nRF52Timers[4]->enableTimer(); + } +} diff --git a/src_h/NRF52_ISR_Timer-Impl.h b/src_h/NRF52_ISR_Timer-Impl.h new file mode 100644 index 0000000..ab331d6 --- /dev/null +++ b/src_h/NRF52_ISR_Timer-Impl.h @@ -0,0 +1,337 @@ +/**************************************************************************************************************************** + NRF52_ISR_Timer-Impl.h + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ + +#pragma once + +//#include "NRF52_ISR_Timer.h" +#include + +NRF52_ISR_Timer::NRF52_ISR_Timer() + : numTimers (-1) +{ +} + +void NRF52_ISR_Timer::init() +{ + unsigned long current_millis = millis(); //elapsed(); + + for (int i = 0; i < MAX_TIMERS; i++) + { + memset((void*) &timer[i], 0, sizeof (timer_t)); + timer[i].prev_millis = current_millis; + } + + numTimers = 0; +} + +void NRF52_ISR_Timer::run() +{ + int i; + unsigned long current_millis; + + // get current time + current_millis = millis(); //elapsed(); + + for (i = 0; i < MAX_TIMERS; i++) + { + + timer[i].toBeCalled = DEFCALL_DONTRUN; + + // no callback == no timer, i.e. jump over empty slots + if (timer[i].callback != NULL) + { + + // is it time to process this timer ? + // see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592 + + if ((current_millis - timer[i].prev_millis) >= timer[i].delay) + { + unsigned long skipTimes = (current_millis - timer[i].prev_millis) / timer[i].delay; + + // update time + timer[i].prev_millis += timer[i].delay * skipTimes; + + // check if the timer callback has to be executed + if (timer[i].enabled) + { + + // "run forever" timers must always be executed + if (timer[i].maxNumRuns == RUN_FOREVER) + { + timer[i].toBeCalled = DEFCALL_RUNONLY; + } + // other timers get executed the specified number of times + else if (timer[i].numRuns < timer[i].maxNumRuns) + { + timer[i].toBeCalled = DEFCALL_RUNONLY; + timer[i].numRuns++; + + // after the last run, delete the timer + if (timer[i].numRuns >= timer[i].maxNumRuns) + { + timer[i].toBeCalled = DEFCALL_RUNANDDEL; + } + } + } + } + } + } + + for (i = 0; i < MAX_TIMERS; i++) + { + if (timer[i].toBeCalled == DEFCALL_DONTRUN) + continue; + + if (timer[i].hasParam) + (*(timer_callback_p)timer[i].callback)(timer[i].param); + else + (*(timer_callback)timer[i].callback)(); + + if (timer[i].toBeCalled == DEFCALL_RUNANDDEL) + deleteTimer(i); + } +} + + +// find the first available slot +// return -1 if none found +int NRF52_ISR_Timer::findFirstFreeSlot() +{ + // all slots are used + if (numTimers >= MAX_TIMERS) + { + return -1; + } + + // return the first slot with no callback (i.e. free) + for (int i = 0; i < MAX_TIMERS; i++) + { + if (timer[i].callback == NULL) + { + return i; + } + } + + // no free slots found + return -1; +} + + +int NRF52_ISR_Timer::setupTimer(unsigned long d, void* f, void* p, bool h, unsigned n) +{ + int freeTimer; + + if (numTimers < 0) + { + init(); + } + + freeTimer = findFirstFreeSlot(); + if (freeTimer < 0) + { + return -1; + } + + if (f == NULL) + { + return -1; + } + + timer[freeTimer].delay = d; + timer[freeTimer].callback = f; + timer[freeTimer].param = p; + timer[freeTimer].hasParam = h; + timer[freeTimer].maxNumRuns = n; + timer[freeTimer].enabled = true; + timer[freeTimer].prev_millis = millis(); + + numTimers++; + + return freeTimer; +} + + +int NRF52_ISR_Timer::setTimer(unsigned long d, timer_callback f, unsigned n) +{ + return setupTimer(d, (void *)f, NULL, false, n); +} + +int NRF52_ISR_Timer::setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n) +{ + return setupTimer(d, (void *)f, p, true, n); +} + +int NRF52_ISR_Timer::setInterval(unsigned long d, timer_callback f) +{ + return setupTimer(d, (void *)f, NULL, false, RUN_FOREVER); +} + +int NRF52_ISR_Timer::setInterval(unsigned long d, timer_callback_p f, void* p) +{ + return setupTimer(d, (void *)f, p, true, RUN_FOREVER); +} + +int NRF52_ISR_Timer::setTimeout(unsigned long d, timer_callback f) +{ + return setupTimer(d, (void *)f, NULL, false, RUN_ONCE); +} + +int NRF52_ISR_Timer::setTimeout(unsigned long d, timer_callback_p f, void* p) +{ + return setupTimer(d, (void *)f, p, true, RUN_ONCE); +} + +bool NRF52_ISR_Timer::changeInterval(unsigned numTimer, unsigned long d) +{ + if (numTimer >= MAX_TIMERS) + { + return false; + } + + // Updates interval of existing specified timer + if (timer[numTimer].callback != NULL) + { + timer[numTimer].delay = d; + timer[numTimer].prev_millis = millis(); + + return true; + } + + // false return for non-used numTimer, no callback + return false; +} + +void NRF52_ISR_Timer::deleteTimer(unsigned timerId) +{ + if (timerId >= MAX_TIMERS) + { + return; + } + + // nothing to delete if no timers are in use + if (numTimers == 0) + { + return; + } + + // don't decrease the number of timers if the specified slot is already empty + if (timer[timerId].callback != NULL) + { + memset((void*) &timer[timerId], 0, sizeof (timer_t)); + timer[timerId].prev_millis = millis(); + + // update number of timers + numTimers--; + } +} + +// function contributed by code@rowansimms.com +void NRF52_ISR_Timer::restartTimer(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return; + } + + timer[numTimer].prev_millis = millis(); +} + + +bool NRF52_ISR_Timer::isEnabled(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return false; + } + + return timer[numTimer].enabled; +} + + +void NRF52_ISR_Timer::enable(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return; + } + + timer[numTimer].enabled = true; +} + + +void NRF52_ISR_Timer::disable(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return; + } + + timer[numTimer].enabled = false; +} + +void NRF52_ISR_Timer::enableAll() +{ + // Enable all timers with a callback assigned (used) + + for (int i = 0; i < MAX_TIMERS; i++) + { + if (timer[i].callback != NULL && timer[i].numRuns == RUN_FOREVER) + { + timer[i].enabled = true; + } + } +} + +void NRF52_ISR_Timer::disableAll() +{ + // Disable all timers with a callback assigned (used) + + for (int i = 0; i < MAX_TIMERS; i++) + { + if (timer[i].callback != NULL && timer[i].numRuns == RUN_FOREVER) + { + timer[i].enabled = false; + } + } +} + +void NRF52_ISR_Timer::toggle(unsigned numTimer) +{ + if (numTimer >= MAX_TIMERS) + { + return; + } + + timer[numTimer].enabled = !timer[numTimer].enabled; +} + + +unsigned NRF52_ISR_Timer::getNumTimers() +{ + return numTimers; +} diff --git a/src_h/NRF52_ISR_Timer.h b/src_h/NRF52_ISR_Timer.h new file mode 100644 index 0000000..50f687e --- /dev/null +++ b/src_h/NRF52_ISR_Timer.h @@ -0,0 +1,173 @@ +/**************************************************************************************************************************** + NRF52_ISR_Timer.h + For NRF52 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/NRF52_TimerInterrupt + Licensed under MIT license + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one NRF52 timer and avoid conflicting with other cores' tasks. + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers + Therefore, their executions are not blocked by bad-behaving functions / tasks. + This important feature is absolutely necessary for mission-critical tasks. + + Based on SimpleTimer - A timer library for Arduino. + Author: mromani@ottotecnica.com + Copyright (c) 2010 OTTOTECNICA Italy + + Based on BlynkTimer.h + Author: Volodymyr Shymanskyy + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 02/11/2020 Initial coding +*****************************************************************************************************************************/ + +#pragma once + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) \ + || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52 platform! Please check your Tools->Board setting. +#endif + +#include + +#include + +#if defined(ARDUINO) + #if ARDUINO >= 100 + #include + #else + #include + #endif +#endif + +#define NRF52_ISR_Timer NRF52_ISRTimer + +typedef void (*timer_callback)(void); +typedef void (*timer_callback_p)(void *); + +class NRF52_ISR_Timer +{ + + public: + // maximum number of timers +#define MAX_TIMERS 16 +#define RUN_FOREVER 0 +#define RUN_ONCE 1 + + // constructor + NRF52_ISR_Timer(); + + void init(); + + // this function must be called inside loop() + void run(); + + // Timer will call function 'f' every 'd' milliseconds forever + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setInterval(unsigned long d, timer_callback f); + + // Timer will call function 'f' with parameter 'p' every 'd' milliseconds forever + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setInterval(unsigned long d, timer_callback_p f, void* p); + + // Timer will call function 'f' after 'd' milliseconds one time + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimeout(unsigned long d, timer_callback f); + + // Timer will call function 'f' with parameter 'p' after 'd' milliseconds one time + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimeout(unsigned long d, timer_callback_p f, void* p); + + // Timer will call function 'f' every 'd' milliseconds 'n' times + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimer(unsigned long d, timer_callback f, unsigned n); + + // Timer will call function 'f' with parameter 'p' every 'd' milliseconds 'n' times + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n); + + // updates interval of the specified timer + bool changeInterval(unsigned numTimer, unsigned long d); + + // destroy the specified timer + void deleteTimer(unsigned numTimer); + + // restart the specified timer + void restartTimer(unsigned numTimer); + + // returns true if the specified timer is enabled + bool isEnabled(unsigned numTimer); + + // enables the specified timer + void enable(unsigned numTimer); + + // disables the specified timer + void disable(unsigned numTimer); + + // enables all timers + void enableAll(); + + // disables all timers + void disableAll(); + + // enables the specified timer if it's currently disabled, and vice-versa + void toggle(unsigned numTimer); + + // returns the number of used timers + unsigned getNumTimers(); + + // returns the number of available timers + unsigned getNumAvailableTimers() + { + return MAX_TIMERS - numTimers; + }; + + private: + // deferred call constants +#define DEFCALL_DONTRUN 0 // don't call the callback function +#define DEFCALL_RUNONLY 1 // call the callback function but don't delete the timer +#define DEFCALL_RUNANDDEL 2 // call the callback function and delete the timer + + // low level function to initialize and enable a new timer + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setupTimer(unsigned long d, void* f, void* p, bool h, unsigned n); + + // find the first available slot + int findFirstFreeSlot(); + + typedef struct + { + unsigned long prev_millis; // value returned by the millis() function in the previous run() call + void* callback; // pointer to the callback function + void* param; // function parameter + bool hasParam; // true if callback takes a parameter + unsigned long delay; // delay value + unsigned maxNumRuns; // number of runs to be executed + unsigned numRuns; // number of executed runs + bool enabled; // true if enabled + unsigned toBeCalled; // deferred function call (sort of) - N.B.: only used in run() + } timer_t; + + volatile timer_t timer[MAX_TIMERS]; + + // actual number of timers in use (-1 means uninitialized) + volatile int numTimers; +}; + + +#include "NRF52_ISR_Timer-Impl.h" +