Hello there! =)
At my Ethernet-Work with multiple sockets at the same time, it came out for me that i have to change the number of sockets used for my requirements in Ethernet.h.
But this wasn't enough for me...i needed multiple sockets, but with different buffer sizes e.g.:
1. socket: 8k Buffer
2. socket: 2k
3. socket: 2k
4. socket: 2k
5. socket: 1k
6. socket: 1k
(sum of all sockets = 16k)
But the library wasn't written to be able to do this, so i changed the library.
It would be very nice, to implement this change (and maybe better coded ) in future updates of the Ethernet library!
I think i made the changes for both, non-fifo and fifo. I only use fifo, so maybe the non-fifo code must be debugged.
The Changed files a the following:
w5100.h (--> new definitions, SMASK and SSIZE are now arrays, new var "USESOCKET")
w5100.cpp (--> init(), write(), read() )
socket.cpp (--> read_data(), socketPeek(), write_data(), socketSend() )
I hope i didn't forgot to post any another changed file!
w5100.h:
w5100.cpp:
socket.cpp:
At my Ethernet-Work with multiple sockets at the same time, it came out for me that i have to change the number of sockets used for my requirements in Ethernet.h.
But this wasn't enough for me...i needed multiple sockets, but with different buffer sizes e.g.:
1. socket: 8k Buffer
2. socket: 2k
3. socket: 2k
4. socket: 2k
5. socket: 1k
6. socket: 1k
(sum of all sockets = 16k)
But the library wasn't written to be able to do this, so i changed the library.
It would be very nice, to implement this change (and maybe better coded ) in future updates of the Ethernet library!
I think i made the changes for both, non-fifo and fifo. I only use fifo, so maybe the non-fifo code must be debugged.
The Changed files a the following:
w5100.h (--> new definitions, SMASK and SSIZE are now arrays, new var "USESOCKET")
w5100.cpp (--> init(), write(), read() )
socket.cpp (--> read_data(), socketPeek(), write_data(), socketSend() )
I hope i didn't forgot to post any another changed file!
w5100.h:
Code:
/*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
*
* 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.
*/
#ifndef W5100_H_INCLUDED
#define W5100_H_INCLUDED
#include <Arduino.h>
#include <SPI.h>
// Safe for all chips
//#define SPI_ETHERNET_SETTINGS SPISettings(14000000, MSBFIRST, SPI_MODE0)
// Safe for W5200 and W5500, but too fast for W5100
// uncomment this if you know you'll never need W5100 support
//#define SPI_ETHERNET_SETTINGS SPISettings(30000000, MSBFIRST, SPI_MODE0)
#define SPI_ETHERNET_SETTINGS SPISettings(40000000, MSBFIRST, SPI_MODE0)
#define MAX_SOCK_NUM 5
//#define W5200_4K_BUFFERS
//#define W5500_4K_BUFFERS
//#define W5500_8K_BUFFERS
//#define W5500_16K_BUFFERS
/*
# uncomment to define sockets of differen sizes, e.g.:
# socket 1 rx/tx = 12k
# socket 2 rx/tx = 2k
# socket 3 rx/tx = 2k
*/
#define W5500_MULTISOCKET
#define W5500_MULTISOCKET_AMOUNT MAX_SOCK_NUM
#define W5500_MULTISOCKET_SIZE_BUFFER0 _8k
#define W5500_MULTISOCKET_SIZE_BUFFER1 _2k
#define W5500_MULTISOCKET_SIZE_BUFFER2 _2k
#define W5500_MULTISOCKET_SIZE_BUFFER3 _2k
#define W5500_MULTISOCKET_SIZE_BUFFER4 _2k
//#define W5500_MULTISOCKET_SIZE_BUFFER5 _1k
//#define W5500_MULTISOCKET_SIZE_BUFFER6 _1k
//#define W5500_MULTISOCKET_SIZE_BUFFER7 2048
#define _1k 0x400
#define _2k 0x800
#define _4k 0x1000
#define _6k 0x1800
#define _8k 0x2000
#define _10k 0x2800
#define _12k 0x3000
#define _14k 0x3800
#define _16k 0x4000
typedef uint8_t SOCKET;
class SnMR {
public:
static const uint8_t CLOSE = 0x00;
static const uint8_t TCP = 0x01;
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;
};
class W5100Class {
public:
static uint8_t init(void);
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); \
}
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)
#undef __GP_REGISTER8
#undef __GP_REGISTER16
#undef __GP_REGISTER_N
// W5100 Socket registers
// ----------------------
private:
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);
}
static uint16_t CH_BASE;
static const uint16_t CH_SIZE = 0x0100;
#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:
static uint8_t chip;
static uint8_t ss_pin;
static uint8_t softReset(void);
static uint8_t isW5100(void);
static uint8_t isW5200(void);
static uint8_t isW5500(void);
public:
static const int SOCKETS = MAX_SOCK_NUM;
#if defined (W5500_MULTISOCKET)
static uint16_t SMASK[W5500_MULTISOCKET_AMOUNT];
static uint16_t SSIZE[W5500_MULTISOCKET_AMOUNT];
#else
static uint16_t SMASK;
static uint16_t SSIZE;
#endif
static uint8_t USESOCKET;
//private:
//receive and transmit have same buffer sizes
static uint16_t SBASE[SOCKETS]; // Tx buffer base address
static uint16_t RBASE[SOCKETS]; // Rx buffer base address
static bool hasOffsetAddressMapping(void) {
if (chip == 55) return true;
return false;
}
static void setSS(uint8_t pin) { ss_pin = pin; }
private:
#if defined(__AVR__)
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__)
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(__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__)
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)
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__)
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
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
#define htons(x) ( (((x)<<8)&0xFF00) | (((x)>>8)&0xFF) )
#define ntohs(x) htons(x)
#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \
((x)<< 8 & 0x00FF0000UL) | \
((x)>> 8 & 0x0000FF00UL) | \
((x)>>24 & 0x000000FFUL) )
#define ntohl(x) htonl(x)
#endif
w5100.cpp:
Code:
/*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
*
* 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.
*/
#include "w5100.h"
#if defined (__arm__) && defined (TEENSYDUINO)
#include "SPIFIFO.h"
#ifdef HAS_SPIFIFO
#define USE_SPIFIFO
#endif
#endif
// If the core library defines a SS pin, use it as the
// default. Otherwise, default the default to pin 10.
#if defined(PIN_SPI_SS)
#define SS_PIN_DEFAULT PIN_SPI_SS
#elif defined(CORE_SS0_PIN)
#define SS_PIN_DEFAULT CORE_SS0_PIN
#else
#define SS_PIN_DEFAULT 10
#endif
// W5100 controller instance
uint16_t W5100Class::SBASE[MAX_SOCK_NUM];
uint16_t W5100Class::RBASE[MAX_SOCK_NUM];
uint16_t W5100Class::CH_BASE;
#if defined (W5500_MULTISOCKET)
uint16_t W5100Class::SSIZE[W5500_MULTISOCKET_AMOUNT];
uint16_t W5100Class::SMASK[W5500_MULTISOCKET_AMOUNT];
#else
uint16_t W5100Class::SSIZE;
uint16_t W5100Class::SMASK;
#endif
uint8_t W5100Class::USESOCKET;
uint8_t W5100Class::chip;
uint8_t W5100Class::ss_pin = SS_PIN_DEFAULT;
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(__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;
#endif
uint8_t W5100Class::init(void)
{
uint16_t TXBUF_BASE, RXBUF_BASE;
uint8_t i;
// 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);
//Serial.println("w5100 init");
#ifdef USE_SPIFIFO
SPI.begin();
SPIFIFO.begin(ss_pin, SPI_CLOCK_24MHz); // W5100 is 14 MHz max
#else
SPI.begin();
initSS();
resetSS();
#endif
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 = 0x4000;
#if defined (W5500_MULTISOCKET)
#ifdef W5500_MULTISOCKET_SIZE_BUFFER0 // different buffersizes
SSIZE[0] = W5500_MULTISOCKET_SIZE_BUFFER0;
SMASK[0] = SSIZE[0] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER1
SSIZE[1] = W5500_MULTISOCKET_SIZE_BUFFER1;
SMASK[1] = SSIZE[1] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER2
SSIZE[2] = W5500_MULTISOCKET_SIZE_BUFFER2;
SMASK[2] = SSIZE[2] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER3
SSIZE[3] = W5500_MULTISOCKET_SIZE_BUFFER3;
SMASK[3] = SSIZE[3] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER4
SSIZE[4] = W5500_MULTISOCKET_SIZE_BUFFER4;
SMASK[4] = SSIZE[4] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER5
SSIZE[5] = W5500_MULTISOCKET_SIZE_BUFFER5;
SMASK[5] = SSIZE[5] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER6
SSIZE[6] = W5500_MULTISOCKET_SIZE_BUFFER6;
SMASK[6] = SSIZE[6] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER7
SSIZE[7] = W5500_MULTISOCKET_SIZE_BUFFER7;
SMASK[7] = SSIZE[7] - 1;
#endif
#elif defined (W5200_4K_BUFFERS)
SSIZE = 4096;
SMASK = 0x0FFF;
#else
SSIZE = 2048; // 2K buffers
SMASK = 0x07FF;
#endif
TXBUF_BASE = 0x8000;
RXBUF_BASE = 0xC000;
#if defined (W5500_MULTISOCKET)
for (i = 0; i<MAX_SOCK_NUM; i++) {
writeSnRX_SIZE(i, SSIZE[i] >> 10);
writeSnTX_SIZE(i, SSIZE[i] >> 10);
}
#else
for (i = 0; i<MAX_SOCK_NUM; i++) {
writeSnRX_SIZE(i, SSIZE >> 10);
writeSnTX_SIZE(i, SSIZE >> 10);
}
#endif
for (; i<8; i++) {
writeSnRX_SIZE(i, 0);
writeSnTX_SIZE(i, 0);
}
// 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 = 0x1000;
#if defined (W5500_MULTISOCKET)
#ifdef W5500_MULTISOCKET_SIZE_BUFFER0 // different buffersizes
SSIZE[0] = W5500_MULTISOCKET_SIZE_BUFFER0;
SMASK[0] = SSIZE[0] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER1
SSIZE[1] = W5500_MULTISOCKET_SIZE_BUFFER1;
SMASK[1] = SSIZE[1] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER2
SSIZE[2] = W5500_MULTISOCKET_SIZE_BUFFER2;
SMASK[2] = SSIZE[2] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER3
SSIZE[3] = W5500_MULTISOCKET_SIZE_BUFFER3;
SMASK[3] = SSIZE[3] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER4
SSIZE[4] = W5500_MULTISOCKET_SIZE_BUFFER4;
SMASK[4] = SSIZE[4] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER5
SSIZE[5] = W5500_MULTISOCKET_SIZE_BUFFER5;
SMASK[5] = SSIZE[5] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER6
SSIZE[6] = W5500_MULTISOCKET_SIZE_BUFFER6;
SMASK[6] = SSIZE[6] - 1;
#endif
#ifdef W5500_MULTISOCKET_SIZE_BUFFER7
SSIZE[7] = W5500_MULTISOCKET_SIZE_BUFFER7;
SMASK[7] = SSIZE[7] - 1;
#endif
#elif defined (W5500_16K_BUFFERS)
SSIZE = 16384; // 16k buffers
SMASK = SSIZE - 1;
#elif defined (W5500_8K_BUFFERS)
SSIZE = 8192; // 8k buffers
SMASK = SSIZE - 1;
#elif defined (W5500_4K_BUFFERS)
SSIZE = 4096; // 4K buffers
SMASK = SSIZE - 1;
#else
SSIZE = 2048; // 2K buffers
SMASK = SSIZE - 1;
#endif
TXBUF_BASE = 0x8000;
RXBUF_BASE = 0xC000;
#if defined (W5500_4K_BUFFERS) || defined (W5500_8K_BUFFERS) || defined (W5500_16K_BUFFERS)
for (i = 0; i<MAX_SOCK_NUM; i++) {
writeSnRX_SIZE(i, SSIZE >> 10);
writeSnTX_SIZE(i, SSIZE >> 10);
}
for (; i<8; i++) {
writeSnRX_SIZE(i, 0);
writeSnTX_SIZE(i, 0);
}
#elif defined (W5500_MULTISOCKET)
for (i = 0; i<MAX_SOCK_NUM; i++) {
writeSnRX_SIZE(i, SSIZE[i] >> 10);
writeSnTX_SIZE(i, SSIZE[i] >> 10);
}
for (; i<8; i++) {
writeSnRX_SIZE(i, 0);
writeSnTX_SIZE(i, 0);
}
#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()) {
#if not defined (W5500_MULTISOCKET)
CH_BASE = 0x0400;
SSIZE = 2048;
SMASK = 0x07FF;
TXBUF_BASE = 0x4000;
RXBUF_BASE = 0x6000;
writeTMSR(0x55);
writeRMSR(0x55);
#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 {
//Serial.println("no chip :-(");
chip = 0;
SPI.endTransaction();
return 0; // no known chip is responding :-(
}
SPI.endTransaction();
// Initialize the socket base addresses
#if defined (W5500_MULTISOCKET)
for (int i = 0; i<MAX_SOCK_NUM; i++) {
SBASE[i] = TXBUF_BASE + SSIZE[i] * i;
RBASE[i] = RXBUF_BASE + SSIZE[i] * i;
}
#else
for (int i = 0; i<MAX_SOCK_NUM; i++) {
SBASE[i] = TXBUF_BASE + SSIZE * i;
RBASE[i] = RXBUF_BASE + SSIZE * i;
}
#endif
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;
//Serial.println("Wiznet soft reset");
// write to reset bit
writeMR(0x80);
// then wait for soft reset to complete
do {
uint8_t mr = readMR();
//Serial.print("mr=");
//Serial.println(mr, HEX);
if (mr == 0) return 1;
delay(1);
} while (++count < 20);
return 0;
}
uint8_t W5100Class::isW5100(void)
{
chip = 51;
//Serial.println("w5100.cpp: detect W5100 chip");
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;
//Serial.println("chip is W5100");
return 1;
}
uint8_t W5100Class::isW5200(void)
{
chip = 52;
//Serial.println("w5100.cpp: detect W5200 chip");
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();
//Serial.print("version=");
//Serial.println(ver);
if (ver != 3) return 0;
//Serial.println("chip is W5200");
return 1;
}
uint8_t W5100Class::isW5500(void)
{
chip = 55;
//Serial.println("w5100.cpp: detect W5500 chip");
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();
//Serial.print("version=");
//Serial.println(ver);
if (ver != 4) return 0;
//Serial.println("chip is W5500");
return 1;
}
#ifdef USE_SPIFIFO
uint16_t W5100Class::write(uint16_t addr, const uint8_t *buf, uint16_t len)
{
uint32_t i;
if (chip == 51) {
for (i = 0; i<len; i++) {
SPIFIFO.write16(0xF000 | (addr >> 8), SPI_CONTINUE);
SPIFIFO.write16((addr << 8) | buf[i]);
addr++;
SPIFIFO.read();
SPIFIFO.read();
}
}
else if (chip == 52) {
SPIFIFO.clear();
SPIFIFO.write16(addr, SPI_CONTINUE);
SPIFIFO.write16(len | 0x8000, SPI_CONTINUE);
for (i = 0; i<len; i++) {
SPIFIFO.write(buf[i], ((i + 1<len) ? SPI_CONTINUE : 0));
SPIFIFO.read();
}
SPIFIFO.read();
SPIFIFO.read();
}
else {
//SPIFIFO.clear();
SPIFIFO.write16(addr, SPI_CONTINUE);
if (addr < 0x100) {
// common registers 00nn
SPIFIFO.write16(0x0400 | *buf++,
((len > 1) ? SPI_CONTINUE : 0));
}
else if (addr < 0x8000) {
// socket registers 10nn, 11nn, 12nn, 13nn, etc
SPIFIFO.write16(((addr << 5) & 0xE000) | 0x0C00 | *buf++,
((len > 1) ? SPI_CONTINUE : 0));
}
else if (addr < 0xC000) {
// transmit buffers 8000-87FF, 8800-8FFF, 9000-97FF, etc
uint16_t block_select_bits = USESOCKET << 13;
SPIFIFO.write16(block_select_bits | 0x1400 | *buf++, ((len > 1) ? SPI_CONTINUE : 0));
}
else {
// receive buffers
uint16_t block_select_bits = USESOCKET << 13;
SPIFIFO.write16(block_select_bits | 0x1C00 | *buf++, ((len > 1) ? SPI_CONTINUE : 0));
}
len--;
while (len >= 2) {
len -= 2;
SPIFIFO.write16((*buf << 8) | *(buf + 1), (len == 0) ? 0 : SPI_CONTINUE);
buf += 2;
SPIFIFO.read();
}
if (len) {
SPIFIFO.write(*buf);
SPIFIFO.read();
}
SPIFIFO.read();
SPIFIFO.read();
}
return len;
}
#else
uint16_t W5100Class::write(uint16_t addr, const uint8_t *buf, uint16_t len)
{
if (chip == 51) {
for (uint16_t i = 0; i<len; i++) {
setSS();
SPI.transfer(0xF0);
SPI.transfer(addr >> 8);
SPI.transfer(addr & 0xFF);
addr++;
SPI.transfer(buf[i]);
resetSS();
}
}
else if (chip == 52) {
setSS();
SPI.transfer(addr >> 8);
SPI.transfer(addr & 0xFF);
SPI.transfer(((len >> 8) & 0x7F) | 0x80);
SPI.transfer(len & 0xFF);
for (uint16_t i = 0; i<len; i++) {
SPI.transfer(buf[i]);
}
resetSS();
}
else {
setSS();
if (addr < 0x100) {
// common registers 00nn
SPI.transfer(0);
SPI.transfer(addr & 0xFF);
SPI.transfer(0x04);
}
else if (addr < 0x8000) {
// socket registers 10nn, 11nn, 12nn, 13nn, etc
SPI.transfer(0);
SPI.transfer(addr & 0xFF);
SPI.transfer(((addr >> 3) & 0xE0) | 0x0C);
}
else if (addr < 0xC000) {
// transmit buffers 8000-87FF, 8800-8FFF, 9000-97FF, etc
// 10## #nnn nnnn nnnn
SPI.transfer(addr >> 8);
SPI.transfer(addr & 0xFF);
#ifdef W5500_16K_BUFFERS
SPI.transfer(0x14); // 16K buffers
#elif defined (W5500_8K_BUFFERS)
SPI.transfer(((addr >> 8) & 0x20) | 0x14); // 8K buffers
#elif defined (W5500_4K_BUFFERS)
SPI.transfer(((addr >> 7) & 0x60) | 0x14); // 4K buffers
#else
SPI.transfer(((addr >> 6) & 0xE0) | 0x14); // 2K buffers
#endif
}
else {
// receive buffers
SPI.transfer(addr >> 8);
SPI.transfer(addr & 0xFF);
#ifdef W5500_16K_BUFFERS
SPI.transfer(0x1C); // 16K buffers
#elif defined (W5500_8K_BUFFERS)
SPI.transfer(((addr >> 8) & 0x20) | 0x1C); // 8K buffers
#elif defined (W5500_4K_BUFFERS)
SPI.transfer(((addr >> 7) & 0x60) | 0x1C); // 4K buffers
#else
SPI.transfer(((addr >> 6) & 0xE0) | 0x1C); // 2K buffers
#endif
}
for (uint16_t i = 0; i<len; i++) {
SPI.transfer(buf[i]);
}
resetSS();
}
return len;
}
#endif
#ifdef USE_SPIFIFO
uint16_t W5100Class::read(uint16_t addr, uint8_t *buf, uint16_t len)
{
uint32_t i;
if (chip == 51) {
for (i = 0; i<len; i++) {
#if 1
SPIFIFO.write(0x0F, SPI_CONTINUE);
SPIFIFO.write16(addr, SPI_CONTINUE);
addr++;
SPIFIFO.read();
SPIFIFO.write(0);
SPIFIFO.read();
buf[i] = SPIFIFO.read();
#endif
#if 0
// this does not work, but why?
SPIFIFO.write16(0x0F00 | (addr >> 8), SPI_CONTINUE);
SPIFIFO.write16(addr << 8);
addr++;
SPIFIFO.read();
buf[i] = SPIFIFO.read();
#endif
}
}
else if (chip == 52) {
// len = 1: write header, write 1 byte, read
// len = 2: write header, write 2 byte, read
// len = 3,5,7
SPIFIFO.clear();
SPIFIFO.write16(addr, SPI_CONTINUE);
SPIFIFO.write16(len & 0x7FFF, SPI_CONTINUE);
SPIFIFO.read();
if (len == 1) {
// read only 1 byte
SPIFIFO.write(0);
SPIFIFO.read();
*buf = SPIFIFO.read();
}
else if (len == 2) {
// read only 2 bytes
SPIFIFO.write16(0);
SPIFIFO.read();
uint32_t val = SPIFIFO.read();
*buf++ = val >> 8;
*buf = val;
}
else if ((len & 1)) {
// read 3 or more, odd length
//Serial.print("W5200 read, len=");
//Serial.println(len);
uint32_t count = len / 2;
SPIFIFO.write16(0, SPI_CONTINUE);
SPIFIFO.read();
do {
if (count > 1) SPIFIFO.write16(0, SPI_CONTINUE);
else SPIFIFO.write(0);
uint32_t val = SPIFIFO.read();
//TODO: WebClient_speedtest with READSIZE 7 is
//dramatically faster with this Serial.print(),
//and the 2 above, but not without both. Why?!
//Serial.println(val, HEX);
*buf++ = val >> 8;
*buf++ = val;
} while (--count > 0);
*buf = SPIFIFO.read();
//Serial.println(*buf, HEX);
}
else {
// read 4 or more, even length
//Serial.print("W5200 read, len=");
//Serial.println(len);
uint32_t count = len / 2 - 1;
SPIFIFO.write16(0, SPI_CONTINUE);
SPIFIFO.read();
do {
SPIFIFO.write16(0, (count > 1) ? SPI_CONTINUE : 0);
uint32_t val = SPIFIFO.read();
*buf++ = val >> 8;
*buf++ = val;
} while (--count > 0);
uint32_t val = SPIFIFO.read();
*buf++ = val >> 8;
*buf++ = val;
}
}
else {
//SPIFIFO.clear();
SPIFIFO.write16(addr, SPI_CONTINUE);
if (addr < 0x100) {
// common registers 00nn
SPIFIFO.write16(0,
((len > 1) ? SPI_CONTINUE : 0));
}
else if (addr < 0x8000) {
// socket registers 10nn, 11nn, 12nn, 13nn, etc
SPIFIFO.write16(((addr << 5) & 0xE000) | 0x0800,
((len > 1) ? SPI_CONTINUE : 0));
}
else if (addr < 0xC000) {
// transmit buffers 8000-87FF, 8800-8FFF, 9000-97FF, etc
uint16_t block_select_bits = USESOCKET << 13;
SPIFIFO.write16(block_select_bits | 0x1000, ((len > 1) ? SPI_CONTINUE : 0));
}
else {
// receive buffers
uint16_t block_select_bits = USESOCKET << 13;
SPIFIFO.write16(block_select_bits | 0x1800, ((len > 1) ? SPI_CONTINUE : 0));
}
SPIFIFO.read();
if (len <= 1) {
*buf++ = SPIFIFO.read();
}
else if (len == 2) {
SPIFIFO.write(0);
*buf++ = SPIFIFO.read();
*buf++ = SPIFIFO.read();
}
else if (len & 1) {
uint32_t count = len >> 1;
SPIFIFO.write16(0, (count > 1) ? SPI_CONTINUE : 0);
*buf++ = SPIFIFO.read();
while (count > 1) {
count--;
SPIFIFO.write16(0, (count > 1) ? SPI_CONTINUE : 0);
uint32_t val = SPIFIFO.read();
*buf++ = val >> 8;
*buf++ = val;
}
uint32_t val = SPIFIFO.read();
*buf++ = val >> 8;
*buf++ = val;
}
else {
SPIFIFO.write16(0, SPI_CONTINUE);
*buf++ = SPIFIFO.read();
uint32_t count = len >> 1;
while (count > 1) {
count--;
if (count > 1) {
SPIFIFO.write16(0, SPI_CONTINUE);
}
else {
SPIFIFO.write(0, 0);
}
uint32_t val = SPIFIFO.read();
*buf++ = val >> 8;
*buf++ = val;
}
*buf = SPIFIFO.read();
}
}
return len;
}
#else
uint16_t W5100Class::read(uint16_t addr, uint8_t *buf, uint16_t len)
{
if (chip == 51) {
for (uint16_t i = 0; i<len; i++) {
setSS();
SPI.transfer(0x0F);
SPI.transfer(addr >> 8);
SPI.transfer(addr & 0xFF);
addr++;
buf[i] = SPI.transfer(0);
resetSS();
}
}
else if (chip == 52) {
setSS();
SPI.transfer(addr >> 8);
SPI.transfer(addr & 0xFF);
SPI.transfer((len >> 8) & 0x7F);
SPI.transfer(len & 0xFF);
for (uint16_t i = 0; i<len; i++) {
buf[i] = SPI.transfer(0);
}
resetSS();
}
else { // W5500
setSS();
if (addr < 0x100) {
// common registers 00nn
SPI.transfer(0);
SPI.transfer(addr & 0xFF);
SPI.transfer(0x00);
}
else if (addr < 0x8000) {
// socket registers 10nn, 11nn, 12nn, 13nn, etc
SPI.transfer(0);
SPI.transfer(addr & 0xFF);
SPI.transfer(((addr >> 3) & 0xE0) | 0x08);
}
else if (addr < 0xC000) {
// transmit buffers 8000-87FF, 8800-8FFF, 9000-97FF, etc
// 10## #nnn nnnn nnnn
SPI.transfer(addr >> 8);
SPI.transfer(addr & 0xFF);
#ifdef W5500_16K_BUFFERS
SPI.transfer(0x10); // 16K buffers (only one socket)
#elif defined (W5500_8K_BUFFERS)
SPI.transfer(((addr >> 8) & 0x20) | 0x10); // 8K buffers
#elif defined (W5500_4K_BUFFERS)
SPI.transfer(((addr >> 7) & 0x60) | 0x10); // 4K buffers
#else
SPI.transfer(((addr >> 6) & 0xE0) | 0x10); // 2K buffers
#endif
}
else {
// receive buffers
SPI.transfer(addr >> 8);
SPI.transfer(addr & 0xFF);
#ifdef W5500_16K_BUFFERS
SPI.transfer(0x18); // 16K buffers (only one socket)
#elif defined (W5500_8K_BUFFERS)
SPI.transfer(((addr >> 8) & 0x20) | 0x18); // 8K buffers
#elif defined (W5500_4K_BUFFERS)
SPI.transfer(((addr >> 7) & 0x60) | 0x18); // 4K buffers
#else
SPI.transfer(((addr >> 6) & 0xE0) | 0x18); // 2K buffers
#endif
}
for (uint16_t i = 0; i<len; i++) {
buf[i] = SPI.transfer(0);
}
resetSS();
}
return len;
}
#endif
void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) {
// Send command to socket
writeSnCR(s, _cmd);
// Wait for command to complete
while (readSnCR(s))
;
}
socket.cpp:
Code:
#include "Ethernet.h"
#include "w5100.h"
#if ARDUINO >= 156 && !defined(ARDUINO_ARCH_PIC32)
extern void yield(void);
#else
#define yield()
#endif
// TODO: randomize this when not using DHCP, but how?
static uint16_t local_port = 49152; // 49152 to 65535
typedef struct {
uint16_t RX_RSR; // Number of bytes received
uint16_t RX_RD; // Address to read
uint16_t TX_FSR; // Free space ready for transmit
uint8_t RX_inc; // how much have we advanced RX_RD
} socketstate_t;
static socketstate_t state[MAX_SOCK_NUM];
static uint16_t getSnTX_FSR(uint8_t s);
static uint16_t getSnRX_RSR(uint8_t s);
static void write_data(uint8_t s, uint16_t offset, const uint8_t *data, uint16_t len);
static void read_data(uint8_t s, uint16_t src, uint8_t *dst, uint16_t len);
/*****************************************/
/* Socket management */
/*****************************************/
void EthernetClass::socketPortRand(uint16_t n)
{
n &= 0x3FFF;
local_port ^= n;
//Serial.printf("socketPortRand %d, srcport=%d\n", n, local_port);
}
uint8_t EthernetClass::socketBegin(uint8_t protocol, uint16_t port)
{
uint8_t s, status[MAX_SOCK_NUM];
//Serial.printf("W5000socket begin, protocol=%d, port=%d\n", protocol, port);
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
// look at all the hardware sockets, use any that are closed (unused)
for (s=0; s < MAX_SOCK_NUM; s++) {
status[s] = W5100.readSnSR(s);
if (status[s] == SnSR::CLOSED) goto makesocket;
}
//Serial.printf("W5000socket step2\n");
// as a last resort, forcibly close any already closing
for (s=0; s < MAX_SOCK_NUM; s++) {
uint8_t stat = status[s];
if (stat == SnSR::LAST_ACK) goto closemakesocket;
if (stat == SnSR::TIME_WAIT) goto closemakesocket;
if (stat == SnSR::FIN_WAIT) goto closemakesocket;
if (stat == SnSR::CLOSING) goto closemakesocket;
}
#if 0
Serial.printf("W5000socket step3\n");
// next, use any that are effectively closed
for (s=0; s < MAX_SOCK_NUM; s++) {
uint8_t stat = status[s];
// TODO: this also needs to check if no more data
if (stat == SnSR::CLOSE_WAIT) goto closemakesocket;
}
#endif
SPI.endTransaction();
return MAX_SOCK_NUM; // all sockets are in use
closemakesocket:
//Serial.printf("W5000socket close\n");
W5100.execCmdSn(s, Sock_CLOSE);
makesocket:
//Serial.printf("W5000socket %d\n", s);
EthernetServer::server_port[s] = 0;
delayMicroseconds(250); // TODO: is this needed??
W5100.writeSnMR(s, protocol);
W5100.writeSnIR(s, 0xFF);
if (port > 0) {
W5100.writeSnPORT(s, port);
} else {
// if don't set the source port, set local_port number.
if (++local_port < 49152) local_port = 49152;
W5100.writeSnPORT(s, local_port);
}
W5100.execCmdSn(s, Sock_OPEN);
state[s].RX_RSR = 0;
state[s].RX_RD = W5100.readSnRX_RD(s); // always zero?
state[s].RX_inc = 0;
state[s].TX_FSR = 0;
//Serial.printf("W5000socket prot=%d, RX_RD=%d\n", W5100.readSnMR(s), state[s].RX_RD);
SPI.endTransaction();
return s;
}
// multicast version to set fields before open thd
uint8_t EthernetClass::socketBeginMulticast(uint8_t protocol, IPAddress ip, uint16_t port)
{
uint8_t s, status[MAX_SOCK_NUM];
//Serial.printf("W5000socket begin, protocol=%d, port=%d\n", protocol, port);
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
// look at all the hardware sockets, use any that are closed (unused)
for (s=0; s < MAX_SOCK_NUM; s++) {
status[s] = W5100.readSnSR(s);
if (status[s] == SnSR::CLOSED) goto makesocket;
}
//Serial.printf("W5000socket step2\n");
// as a last resort, forcibly close any already closing
for (s=0; s < MAX_SOCK_NUM; s++) {
uint8_t stat = status[s];
if (stat == SnSR::LAST_ACK) goto closemakesocket;
if (stat == SnSR::TIME_WAIT) goto closemakesocket;
if (stat == SnSR::FIN_WAIT) goto closemakesocket;
if (stat == SnSR::CLOSING) goto closemakesocket;
}
#if 0
Serial.printf("W5000socket step3\n");
// next, use any that are effectively closed
for (s=0; s < MAX_SOCK_NUM; s++) {
uint8_t stat = status[s];
// TODO: this also needs to check if no more data
if (stat == SnSR::CLOSE_WAIT) goto closemakesocket;
}
#endif
SPI.endTransaction();
return MAX_SOCK_NUM; // all sockets are in use
closemakesocket:
//Serial.printf("W5000socket close\n");
W5100.execCmdSn(s, Sock_CLOSE);
makesocket:
//Serial.printf("W5000socket %d\n", s);
EthernetServer::server_port[s] = 0;
delayMicroseconds(250); // TODO: is this needed??
W5100.writeSnMR(s, protocol);
W5100.writeSnIR(s, 0xFF);
if (port > 0) {
W5100.writeSnPORT(s, port);
} else {
// if don't set the source port, set local_port number.
if (++local_port < 49152) local_port = 49152;
W5100.writeSnPORT(s, local_port);
}
// 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];
W5100.writeSnDIPR(s, ip.raw_address()); //239.255.0.1
W5100.writeSnDPORT(s, port);
W5100.writeSnDHAR(s, mac);
W5100.execCmdSn(s, Sock_OPEN);
state[s].RX_RSR = 0;
state[s].RX_RD = W5100.readSnRX_RD(s); // always zero?
state[s].RX_inc = 0;
state[s].TX_FSR = 0;
//Serial.printf("W5000socket prot=%d, RX_RD=%d\n", W5100.readSnMR(s), state[s].RX_RD);
SPI.endTransaction();
return s;
}
// Return the socket's status
//
uint8_t EthernetClass::socketStatus(uint8_t s)
{
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
uint8_t status = W5100.readSnSR(s);
SPI.endTransaction();
return status;
}
// Immediately close. If a TCP connection is established, the
// remote host is left unaware we closed.
//
void EthernetClass::socketClose(uint8_t s)
{
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.execCmdSn(s, Sock_CLOSE);
SPI.endTransaction();
}
// Place the socket in listening (server) mode
//
uint8_t EthernetClass::socketListen(uint8_t s)
{
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
if (W5100.readSnSR(s) != SnSR::INIT) {
SPI.endTransaction();
return 0;
}
W5100.execCmdSn(s, Sock_LISTEN);
SPI.endTransaction();
return 1;
}
// establish a TCP connection in Active (client) mode.
//
void EthernetClass::socketConnect(uint8_t s, uint8_t * addr, uint16_t port)
{
// set destination IP
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.writeSnDIPR(s, addr);
W5100.writeSnDPORT(s, port);
W5100.execCmdSn(s, Sock_CONNECT);
SPI.endTransaction();
}
// Gracefully disconnect a TCP connection.
//
void EthernetClass::socketDisconnect(uint8_t s)
{
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.execCmdSn(s, Sock_DISCON);
SPI.endTransaction();
}
/*****************************************/
/* Socket Data Receive Functions */
/*****************************************/
static uint16_t getSnRX_RSR(uint8_t s)
{
#if 1
uint16_t val, prev;
prev = W5100.readSnRX_RSR(s);
while (1) {
val = W5100.readSnRX_RSR(s);
if (val == prev) {
state[s].RX_RSR = val;
return val;
}
prev = val;
}
#else
uint16_t val = W5100.readSnRX_RSR(s);
state[s].RX_RSR = val;
return val;
#endif
}
static void read_data(uint8_t s, uint16_t src, uint8_t *dst, uint16_t len)
{
uint16_t size;
uint16_t src_mask;
uint16_t src_ptr;
//Serial.printf("read_data, len=%d, at:%d\n", len, src);
//Serial.printf("read: %d\r\n", s);
W5100.USESOCKET = s; // tell w5100.cpp to which socket to handle
#if defined (W5500_MULTISOCKET)
src_mask = (uint16_t)src & W5100.SMASK[s];
src_ptr = W5100.RBASE[s] + src_mask;
if (W5100.hasOffsetAddressMapping() || src_mask + len <= W5100.SSIZE[s]) {
W5100.read(src_ptr, dst, len);
}
else {
size = W5100.SSIZE[s] - src_mask;
W5100.read(src_ptr, dst, size);
dst += size;
W5100.read(W5100.RBASE[s], dst, len - size);
}
#else
src_mask = (uint16_t)src & W5100.SMASK;
src_ptr = W5100.RBASE[s] + src_mask;
if (W5100.hasOffsetAddressMapping() || src_mask + len <= W5100.SSIZE) {
W5100.read(src_ptr, dst, len);
}
else {
size = W5100.SSIZE - src_mask;
W5100.read(src_ptr, dst, size);
dst += size;
W5100.read(W5100.RBASE[s], dst, len - size);
}
#endif
}
// Receive data. Returns size, or -1 for no data, or 0 if connection closed
//
int EthernetClass::socketRecv(uint8_t s, uint8_t *buf, int16_t len)
{
// Check how much data is available
int ret = state[s].RX_RSR;
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
if (ret < len) {
ret = getSnRX_RSR(s);
}
if (ret == 0) {
// No data available.
uint8_t status = W5100.readSnSR(s);
if ( status == SnSR::LISTEN || status == SnSR::CLOSED ||
status == SnSR::CLOSE_WAIT ) {
// The remote end has closed its side of the connection,
// so this is the eof state
ret = 0;
} else {
// The connection is still up, but there's no data waiting to be read
ret = -1;
}
} else {
if (ret > len) ret = len; // more data available than buffer length
uint16_t ptr = state[s].RX_RD;
read_data(s, ptr, buf, ret);
ptr += ret;
state[s].RX_RD = ptr;
state[s].RX_RSR -= ret;
uint16_t inc = state[s].RX_inc + ret;
if (inc >= 250 || state[s].RX_RSR == 0) {
state[s].RX_inc = 0;
W5100.writeSnRX_RD(s, ptr);
W5100.execCmdSn(s, Sock_RECV);
//Serial.printf("Sock_RECV cmd, RX_RD=%d\n", state[s].RX_RD);
} else {
state[s].RX_inc = inc;
}
}
SPI.endTransaction();
return ret;
}
uint16_t EthernetClass::socketRecvAvailable(uint8_t s)
{
uint16_t ret = state[s].RX_RSR;
if (ret == 0) {
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
ret = getSnRX_RSR(s);
SPI.endTransaction();
}
//Serial.printf("sock.recvAvailable s=%d, num=%d\n", s, ret);
return ret;
}
// get the first byte in the receive queue (no checking)
//
uint8_t EthernetClass::socketPeek(uint8_t s)
{
uint8_t b;
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.USESOCKET = s; // tell w5100.cpp to which socket to handle
#if defined (W5500_MULTISOCKET)
uint16_t ptr = state[s].RX_RD;
W5100.read((ptr & W5100.SMASK[s]) + W5100.RBASE[s], &b, 1);
SPI.endTransaction();
return b;
#else
uint16_t ptr = state[s].RX_RD;
W5100.read((ptr & W5100.SMASK) + W5100.RBASE[s], &b, 1);
SPI.endTransaction();
return b;
#endif
}
/*****************************************/
/* Socket Data Transmit Functions */
/*****************************************/
static uint16_t getSnTX_FSR(uint8_t s)
{
uint16_t val, prev;
prev = W5100.readSnTX_FSR(s);
while (1) {
val = W5100.readSnTX_FSR(s);
if (val == prev) {
state[s].TX_FSR = val;
return val;
}
prev = val;
}
}
static void write_data(uint8_t s, uint16_t data_offset, const uint8_t *data, uint16_t len)
{
uint16_t ptr = W5100.readSnTX_WR(s);
ptr += data_offset;
//Serial.printf("write: %d\r\n", s);
W5100.USESOCKET = s; // tell w5100.cpp to which socket to handle
#if defined (W5500_MULTISOCKET)
uint16_t offset = ptr & W5100.SMASK[s];
uint16_t dstAddr = offset + W5100.SBASE[s];
if (W5100.hasOffsetAddressMapping() || offset + len <= W5100.SSIZE[s]) {
W5100.write(dstAddr, data, len);
}
else {
// Wrap around circular buffer
uint16_t size = W5100.SSIZE[s] - offset;
W5100.write(dstAddr, data, size);
W5100.write(W5100.SBASE[s], data + size, len - size);
}
#else
uint16_t offset = ptr & W5100.SMASK;
uint16_t dstAddr = offset + W5100.SBASE[s];
if (W5100.hasOffsetAddressMapping() || offset + len <= W5100.SSIZE) {
W5100.write(dstAddr, data, len);
}
else {
// Wrap around circular buffer
uint16_t size = W5100.SSIZE - offset;
W5100.write(dstAddr, data, size);
W5100.write(W5100.SBASE[s], data + size, len - size);
}
#endif
ptr += len;
W5100.writeSnTX_WR(s, ptr);
}
/**
* @brief This function used to send the data in TCP mode
* @return 1 for success else 0.
*/
uint16_t EthernetClass::socketSend(uint8_t s, const uint8_t * buf, uint16_t len)
{
uint8_t status=0;
uint16_t ret=0;
uint16_t freesize=0;
#if defined (W5500_MULTISOCKET)
if (len > W5100.SSIZE[s]) {
ret = W5100.SSIZE[s]; // check size not to exceed MAX size.
}
else {
ret = len;
}
#else
if (len > W5100.SSIZE) {
ret = W5100.SSIZE; // check size not to exceed MAX size.
}
else {
ret = len;
}
#endif
// if freebuf is available, start.
do {
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
freesize = getSnTX_FSR(s);
status = W5100.readSnSR(s);
SPI.endTransaction();
if ((status != SnSR::ESTABLISHED) && (status != SnSR::CLOSE_WAIT)) {
ret = 0;
break;
}
yield();
} while (freesize < ret);
// copy data
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
write_data(s, 0, (uint8_t *)buf, ret);
W5100.execCmdSn(s, Sock_SEND);
/* +2008.01 bj */
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) {
/* m2008.01 [bj] : reduce code */
if ( W5100.readSnSR(s) == SnSR::CLOSED ) {
SPI.endTransaction();
return 0;
}
SPI.endTransaction();
yield();
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
}
/* +2008.01 bj */
W5100.writeSnIR(s, SnIR::SEND_OK);
SPI.endTransaction();
return ret;
}
uint16_t EthernetClass::socketBufferData(uint8_t s, uint16_t offset, const uint8_t* buf, uint16_t len)
{
//Serial.printf(" bufferData, offset=%d, len=%d\n", offset, len);
uint16_t ret =0;
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
uint16_t txfree = getSnTX_FSR(s);
if (len > txfree) {
ret = txfree; // check size not to exceed MAX size.
} else {
ret = len;
}
write_data(s, offset, buf, ret);
SPI.endTransaction();
return ret;
}
int EthernetClass::socketStartUDP(uint8_t s, uint8_t* addr, uint16_t port)
{
if ( ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
((port == 0x00)) ) {
return 0;
}
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.writeSnDIPR(s, addr);
W5100.writeSnDPORT(s, port);
SPI.endTransaction();
return 1;
}
int EthernetClass::socketSendUDP(uint8_t s)
{
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.execCmdSn(s, Sock_SEND);
/* +2008.01 bj */
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) {
if (W5100.readSnIR(s) & SnIR::TIMEOUT) {
/* +2008.01 [bj]: clear interrupt */
W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT));
SPI.endTransaction();
//Serial.printf("sendUDP timeout\n");
return 0;
}
SPI.endTransaction();
yield();
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
}
/* +2008.01 bj */
W5100.writeSnIR(s, SnIR::SEND_OK);
SPI.endTransaction();
//Serial.printf("sendUDP ok\n");
/* Sent ok */
return 1;
}