Created
October 27, 2016 00:18
-
-
Save betzrhodes/f41474f90865fb99109cc816df8ffc46 to your computer and use it in GitHub Desktop.
Wiznet with PHY getter and setter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// CONTROL PHASE | |
// -------------------------------------------------- | |
// BLOCK SELECT BITS | |
const W5500_COMMON_REGISTER = 0x00; | |
const W5500_S0_REGISTER = 0x08; | |
const W5500_S0_TX_BUFFER = 0x10; | |
const W5500_S0_RX_BUFFER = 0x18; | |
const W5500_S1_REGISTER = 0x28; | |
const W5500_S1_TX_BUFFER = 0x30; | |
const W5500_S1_RX_BUFFER = 0x38; | |
const W5500_S2_REGISTER = 0x48; | |
const W5500_S2_TX_BUFFER = 0x50; | |
const W5500_S2_RX_BUFFER = 0x58; | |
const W5500_S3_REGISTER = 0x68; | |
const W5500_S3_TX_BUFFER = 0x70; | |
const W5500_S3_RX_BUFFER = 0x78; | |
const W5500_S4_REGISTER = 0x88; | |
const W5500_S4_TX_BUFFER = 0x90; | |
const W5500_S4_RX_BUFFER = 0x98; | |
const W5500_S5_REGISTER = 0xA8; | |
const W5500_S5_TX_BUFFER = 0xB0; | |
const W5500_S5_RX_BUFFER = 0xB8; | |
const W5500_S6_REGISTER = 0xC8; | |
const W5500_S6_TX_BUFFER = 0xD0; | |
const W5500_S6_RX_BUFFER = 0xD8; | |
const W5500_S7_REGISTER = 0xE8; | |
const W5500_S7_TX_BUFFER = 0xF0; | |
const W5500_S7_RX_BUFFER = 0xF8; | |
// READ/WRITE BIT | |
const W5500_READ_COMMAND = 0x00; | |
const W5500_WRITE_COMMAND = 0x04; | |
// SPI OPPERATION MODE | |
const W5500_VARIABLE_DATA_LENGTH = 0x00; | |
const W5500_FIXED_DATA_LENGTH_1 = 0x01; | |
const W5500_FIXED_DATA_LENGTH_2 = 0x02; | |
const W5500_FIXED_DATA_LENGTH_4 = 0x03; | |
// COMMON REGISTERS OFFSET ADDRESSES | |
// -------------------------------------------------- | |
// MR | |
const W5500_MODE = 0x0000; | |
//GWR | |
const W5500_GATEWAY_ADDR_0 = 0x0001; | |
const W5500_GATEWAY_ADDR_1 = 0x0002; | |
const W5500_GATEWAY_ADDR_2 = 0x0003; | |
const W5500_GATEWAY_ADDR_3 = 0x0004; | |
//SUBR | |
const W5500_SUBNET_MASK_ADDR_0 = 0x0005; | |
const W5500_SUBNET_MASK_ADDR_1 = 0x0006; | |
const W5500_SUBNET_MASK_ADDR_2 = 0x0007; | |
const W5500_SUBNET_MASK_ADDR_3 = 0x0008; | |
//SHAR | |
const W5500_SOURCE_HW_ADDR_0 = 0x0009; | |
const W5500_SOURCE_HW_ADDR_1 = 0x000A; | |
const W5500_SOURCE_HW_ADDR_2 = 0x000B; | |
const W5500_SOURCE_HW_ADDR_3 = 0x000C; | |
const W5500_SOURCE_HW_ADDR_4 = 0x000D; | |
const W5500_SOURCE_HW_ADDR_5 = 0x000E; | |
//SIPR | |
const W5500_SOURCE_IP_ADDR_0 = 0x000F; | |
const W5500_SOURCE_IP_ADDR_1 = 0x0010; | |
const W5500_SOURCE_IP_ADDR_2 = 0x0011; | |
const W5500_SOURCE_IP_ADDR_3 = 0x0012; | |
// INTLEVEL | |
const W5500_INTERRUPT_LOW_LEVEL_TIMER_0 = 0x0013; | |
const W5500_INTERRUPT_LOW_LEVEL_TIMER_1 = 0x0014; | |
//IR | |
const W5500_INTERRUPT = 0x0015; | |
// IMR | |
const W5500_INTERRUPT_MASK = 0x0016; | |
// SIR | |
const W5500_SOCKET_INTERRUPT = 0x0017; | |
// SIMR | |
const W5500_SOCKET_INTERRUPT_MASK = 0x0018; | |
// RTR | |
const W5500_RETRY_TIME_0 = 0x0019; | |
const W5500_RETRY_TIME_1 = 0x001A; | |
// RCR | |
const W5500_RETRY_COUNT = 0x001B; | |
// PHYCFGR | |
const W5500_PHY_CONFIG = 0x002E; | |
const W5500_CHIP_VERSION = 0x0039; | |
// SOCKET REGISTER OFFSET ADDRESSES | |
// -------------------------------------------------- | |
const W5500_SOCKET_MODE = 0x0000; | |
const W5500_SOCKET_COMMAND = 0x0001; | |
const W5500_SOCKET_N_INTERRUPT = 0x0002; | |
const W5500_SOCKET_STATUS = 0x0003; | |
const W5500_SOCKET_SOURCE_PORT_0 = 0x0004; | |
const W5500_SOCKET_SOURCE_PORT_1 = 0x0005; | |
const W5500_SOCKET_DEST_HW_ADDR_0 = 0x0006; | |
const W5500_SOCKET_DEST_HW_ADDR_1 = 0x0007; | |
const W5500_SOCKET_DEST_HW_ADDR_2 = 0x0008; | |
const W5500_SOCKET_DEST_HW_ADDR_3 = 0x0009; | |
const W5500_SOCKET_DEST_HW_ADDR_4 = 0x000A; | |
const W5500_SOCKET_DEST_HW_ADDR_5 = 0x000B; | |
const W5500_SOCKET_DEST_IP_ADDR_0 = 0x000C; | |
const W5500_SOCKET_DEST_IP_ADDR_1 = 0x000D; | |
const W5500_SOCKET_DEST_IP_ADDR_2 = 0x000E; | |
const W5500_SOCKET_DEST_IP_ADDR_3 = 0x000F; | |
const W5500_SOCKET_DEST_PORT_0 = 0x0010; | |
const W5500_SOCKET_DEST_PORT_1 = 0x0011; | |
const W5500_SOCKET_RX_BUFFER_SIZE = 0x001E; | |
const W5500_SOCKET_TX_BUFFER_SIZE = 0x001F; | |
// SOCKET TX FREE SIZE REGISTER (Sn_TX_FREE_SIZE) | |
const W5500_SOCKET_TX_SIZE_R1 = 0x0020; | |
const W5500_SOCKET_TX_SIZE_R2 = 0x0021; | |
// SOCKET TX READ POINTER | |
const W5500_SOCKET_TX_RP_R1 = 0x0022; | |
const W5500_SOCKET_TX_RP_R2 = 0x0023; | |
// SOCKET TX WRITE POINTER | |
const W5500_SOCKET_TX_WP_R1 = 0x0024; | |
const W5500_SOCKET_TX_WP_R2 = 0x0025; | |
// SOCKET RX RECEIVED SIZE REGISTER (Sn_RX_RSR) | |
const W5500_SOCKET_RX_SIZE_R1 = 0x0026; | |
const W5500_SOCKET_RX_SIZE_R2 = 0x0027; | |
// SOCKET RX READ POINTER (Sn_RX_RD) | |
const W5500_SOCKET_RX_RP_R1 = 0x0028; | |
const W5500_SOCKET_RX_RP_R2 = 0x0029; | |
// SOCKET N INTERRUPT MASK (Sn_IMR) | |
const W5500_SOCKET_N_INTERRUPT_MASK = 0x002C; | |
// -------------------------------------------------- | |
// MODES | |
const W5500_SW_RESET = 0x80; | |
const W5500_WAKE_ON_LAN = 0x20; | |
const W5500_PING_BLOCK = 0x10; | |
const W5500_PPPoE = 0x08; | |
const W5500_FORCE_ARP = 0x01; | |
const W5500_DEFAULT_MODE = 0x00; | |
// PHY MODES | |
const W5500_PHY_POWER_DOWN = 0x30; | |
const W5500_PHY_ALL_ENABLED = 0x38; | |
const W5500_PHY_MODE_MASK = 0xC7; | |
// SOCKET MODES (Sn_MR) | |
const W5500_SOCKET_MODE_MULTI = 0x80; | |
const W5500_SOCKET_MODE_BROADCAST_BLOCKING = 0x40; | |
const W5500_SOCKET_MODE_NO_DELAY_ACK = 0x20; | |
const W5500_SOCKET_MODE_UNICAST_BLOCKING = 0x10; | |
const W5500_SOCKET_MODE_CLOSED = 0x00; | |
const W5500_SOCKET_MODE_TCP = 0x01; | |
const W5500_SOCKET_MODE_UDP = 0x02; | |
const W5500_SOCKET_MODE_MACRAW = 0x03; | |
// SOCKET COMMANDS (Sn_CR) | |
const W5500_SOCKET_OPEN = 0x01; | |
const W5500_SOCKET_LISTEN = 0x02; | |
const W5500_SOCKET_CONNECT = 0x04; | |
const W5500_SOCKET_DISCONNECT = 0x08; | |
const W5500_SOCKET_CLOSE = 0x10; | |
const W5500_SOCKET_SEND = 0x20; | |
const W5500_SOCKET_SEND_MAC = 0x21; | |
const W5500_SOCKET_SEND_KEEP = 0x22; | |
const W5500_SOCKET_RECEIVE = 0x40; | |
// SOCKET STATUS (Sn_SR) | |
const W5500_SOCKET_STATUS_CLOSED = 0x00; | |
const W5500_SOCKET_STATUS_INIT = 0x13; | |
const W5500_SOCKET_STATUS_LISTEN = 0x14; | |
const W5500_SOCKET_STATUS_ESTABLISHED = 0x17; | |
const W5500_SOCKET_STATUS_CLOSE_WAIT = 0x1C; | |
const W5500_SOCKET_STATUS_UDP = 0x22; | |
const W5500_SOCKET_STATUS_MACRAW = 0x42; | |
const W5500_SOCKET_STATUS_SYNSENT = 0x15; | |
const W5500_SOCKET_STATUS_SYNRECV = 0x16; | |
const W5500_SOCKET_STATUS_FIN_WAIT = 0x18; | |
const W5500_SOCKET_STATUS_CLOSING = 0x1A; | |
const W5500_SOCKET_STATUS_TIME_WAIT = 0x1B; | |
const W5500_SOCKET_STATUS_LAST_ACK = 0x1D; | |
// INTERRUPT TYPES | |
const W5500_CONFLICT_INT_TYPE = 0x80; | |
const W5500_UNREACH_INT_TYPE = 0x40; | |
const W5500_PPPoE_INT_TYPE = 0x20; | |
const W5500_MAGIC_PACKET_TYPE = 0x10; | |
const W5500_NONE_INT_TYPE = 0x00; | |
// SOCKET INTERRUPTS | |
const W5500_S0_INTERRUPT = 0x01; | |
const W5500_S1_INTERRUPT = 0x02; | |
const W5500_S2_INTERRUPT = 0x04; | |
const W5500_S3_INTERRUPT = 0x08; | |
const W5500_S4_INTERRUPT = 0x10; | |
const W5500_S5_INTERRUPT = 0x20; | |
const W5500_S6_INTERRUPT = 0x40; | |
const W5500_S7_INTERRUPT = 0x80; | |
const W5500_DISABLE_SOCKET_INTERRUPTS = 0x00; | |
// SOCKET INTERRUPT TYPES | |
const W5500_SEND_COMPLETE_INT_TYPE = 0x10; | |
const W5500_TIMEOUT_INT_TYPE = 0x08; | |
const W5500_DATA_RECEIVED_INT_TYPE = 0x04; | |
const W5500_DISCONNECTED_INT_TYPE = 0x02; | |
const W5500_CONNECTED_INT_TYPE = 0x01; | |
/* -------------------------------------------------- | |
* W5500 driver | |
* this driver supports only the first 4 sockets (0-3) | |
-------------------------------------------------- */ | |
class W5500 { | |
static VERSION = [0, 1, 0]; | |
} | |
class W5500.Connection { | |
socket = null; | |
state = null; | |
handlers = null; | |
settings = null; | |
/*************************************************************************** | |
* Constructor | |
* Returns: null | |
* Parameters: | |
* _socket - socket number of the connection (integer) | |
* _state - current state of the connection (string) | |
* _settings - table of connection settings | |
* _handlers(optional) - table of callback functions | |
* (connect, disconnect, transmit, receive) | |
**************************************************************************/ | |
constructor(_socket, _state, _settings, _handlers = {}) { | |
socket = _socket; | |
state = _state; | |
handlers = _handlers; | |
settings = _settings; | |
} | |
/*************************************************************************** | |
* setDisconnectHandler | |
* Returns: this | |
* Parameters: | |
* cb - function to called when disconnect interrupt triggered | |
**************************************************************************/ | |
function setDisconnectHandler(cb) { | |
handlers["disconnect"] <- cb; | |
return this; | |
} | |
/*************************************************************************** | |
* setReceiveHandler | |
* Returns: this | |
* Parameters: | |
* cb - function to called when data received interrupt triggered | |
**************************************************************************/ | |
function setReceiveHandler(cb) { | |
handlers["receive"] <- cb; | |
return this; | |
} | |
/*************************************************************************** | |
* setTransmitHandler | |
* Returns: this | |
* Parameters: | |
* cb - function to called when transmit/timeout interrupt triggered | |
**************************************************************************/ | |
function setTransmitHandler(cb) { | |
handlers["transmit"] <- cb; | |
return this; | |
} | |
/*************************************************************************** | |
* setConnectHandler | |
* Returns: this | |
* Parameters: | |
* cb - function to called when connect/timeout interrupt triggered | |
**************************************************************************/ | |
function setConnectHandler(cb) { | |
handlers["connect"] <- cb; | |
return this; | |
} | |
/*************************************************************************** | |
* setState | |
* Returns: this | |
* Parameters: | |
* state - new conneciton state | |
**************************************************************************/ | |
function setState(state) { | |
state = state; | |
return this; | |
} | |
/*************************************************************************** | |
* setSourcePort | |
* Returns: this | |
* Parameters: | |
* port - source port | |
**************************************************************************/ | |
function setSourcePort(port) { | |
settings["sourcePort"] <- port; | |
return this; | |
} | |
/*************************************************************************** | |
* setSourcePort | |
* Returns: handler function or null | |
* Parameters: | |
* handlerName - name of handler | |
**************************************************************************/ | |
function getHandler(handlerName) { | |
return (handlerName in handlers) ? handlers[handlerName] : null; | |
} | |
} | |
class W5500.Driver { | |
// Chip can support 8, only 4 supported in the driver code | |
static TOTAL_SUPPORTED_SOCKETS = 4; | |
static MAX_TX_MEM_BUFFER = 16; | |
static MAX_RX_MEM_BUFFER = 16; | |
// CLASS VARIABLES | |
_spi = null; | |
_cs = null; | |
_resetPin = null; | |
socketMemory = null; | |
/*************************************************************************** | |
* Constructor | |
* Returns: null | |
* Parameters: | |
* spi - configured spi, W5500 supports spi mode 0 or 3 | |
* cs(optional) - configured chip select pin | |
* reset(optional) - configured reset pin | |
**************************************************************************/ | |
constructor(spi, cs = null, resetPin = null) { | |
_spi = spi; | |
_cs = cs; | |
_resetPin = resetPin; | |
_setMemDefaults(); | |
} | |
// GETTERS AND SETTERS | |
// --------------------------------------------- | |
/*************************************************************************** | |
* setMode | |
* Returns: this | |
* Parameters: | |
* mode - select mode using MODE constants or-ed together | |
**************************************************************************/ | |
function setMode(mode) { | |
writeReg(W5500_MODE, W5500_COMMON_REGISTER, mode); | |
return this; | |
} | |
/*************************************************************************** | |
* setPHYMode | |
* Returns: this | |
* Parameters: | |
* mode - select mode using MODE constants | |
**************************************************************************/ | |
function setPHYMode(mode) { | |
local bits = getPYHConfigReg() && W5500_PHY_MODE_MASK; | |
writeReg(W5500_PHY_CONFIG, W5500_COMMON_REGISTER, bits || mode); | |
return this; | |
} | |
/*************************************************************************** | |
* setSocketMode | |
* Returns: this | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
* mode - select mode using W5500_SOCKET_MODE constant | |
**************************************************************************/ | |
function setSocketMode(socket, mode) { | |
local bsb = _getSocketRegBlockSelectBit(socket) | |
writeReg(W5500_SOCKET_MODE, bsb, mode); | |
return this; | |
} | |
/*************************************************************************** | |
* setMemory | |
* Returns: this | |
* Parameters: | |
* memory - an array of four integers with the desired transmit memory | |
* allotment for each socket (supported values are 0, 1, 2, 4, 8, 16) | |
* dir - a string containing the transmition direction, accepted values | |
* are "tx" or "rx" | |
**************************************************************************/ | |
function setMemory(memory, dir) { | |
local memoryBufferSize = 16; | |
local addr = (dir == "rx") ? W5500_SOCKET_RX_BUFFER_SIZE : W5500_SOCKET_TX_BUFFER_SIZE; | |
local bits = 0x00; | |
local total = 0; | |
foreach (socket, mem_size in memory) { | |
local socket_mem = 0x00; | |
local bytes = 0; | |
// adjust memory size if total memory is used up | |
if ( total + mem_size > memoryBufferSize) { | |
mem_size = memoryBufferSize - total; | |
if (mem_size < 0) mem_size = 0; | |
} | |
if(mem_size == memoryBufferSize) { | |
bytes = 16384; | |
} else if (mem_size >= 8) { | |
mem_size = 8; | |
bytes = 8192; | |
} else if (mem_size >= 4) { | |
mem_size = 4; | |
bytes = 4096; | |
} else if (mem_size >= 2) { | |
mem_size = 2; | |
bytes = 2048; | |
} else if (mem_size >= 1) { | |
mem_size = 1; | |
bytes = 1024; | |
} else { | |
mem_size = 0; | |
bytes = 0; | |
} | |
total += mem_size; | |
socketMemory[dir][socket] = bytes; | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
writeReg(addr, bsb, mem_size); | |
} | |
return this; | |
} | |
/*************************************************************************** | |
* setGatewayAddr | |
* Returns: this | |
* Parameters: | |
* addr - an array of four integers with the gateway IP address | |
**************************************************************************/ | |
function setGatewayAddr(addr) { | |
writeReg(W5500_GATEWAY_ADDR_0, W5500_COMMON_REGISTER, addr[0]); | |
writeReg(W5500_GATEWAY_ADDR_1, W5500_COMMON_REGISTER, addr[1]); | |
writeReg(W5500_GATEWAY_ADDR_2, W5500_COMMON_REGISTER, addr[2]); | |
writeReg(W5500_GATEWAY_ADDR_3, W5500_COMMON_REGISTER, addr[3]); | |
return this; | |
} | |
/*************************************************************************** | |
* setSubnet | |
* Returns: this | |
* Parameters: | |
* addr - an array of four integers with the subnet address | |
**************************************************************************/ | |
function setSubnet(addr) { | |
writeReg(W5500_SUBNET_MASK_ADDR_0, W5500_COMMON_REGISTER, addr[0]); | |
writeReg(W5500_SUBNET_MASK_ADDR_1, W5500_COMMON_REGISTER, addr[1]); | |
writeReg(W5500_SUBNET_MASK_ADDR_2, W5500_COMMON_REGISTER, addr[2]); | |
writeReg(W5500_SUBNET_MASK_ADDR_3, W5500_COMMON_REGISTER, addr[3]); | |
return this; | |
} | |
/*************************************************************************** | |
* setSourceHWAddr | |
* Returns: this | |
* Parameters: | |
* addr - an array of 6 integers with the mac address for the | |
* source hardware | |
**************************************************************************/ | |
function setSourceHWAddr(addr) { | |
writeReg(W5500_SOURCE_HW_ADDR_0, W5500_COMMON_REGISTER, addr[0]); | |
writeReg(W5500_SOURCE_HW_ADDR_1, W5500_COMMON_REGISTER, addr[1]); | |
writeReg(W5500_SOURCE_HW_ADDR_2, W5500_COMMON_REGISTER, addr[2]); | |
writeReg(W5500_SOURCE_HW_ADDR_3, W5500_COMMON_REGISTER, addr[3]); | |
writeReg(W5500_SOURCE_HW_ADDR_4, W5500_COMMON_REGISTER, addr[4]); | |
writeReg(W5500_SOURCE_HW_ADDR_5, W5500_COMMON_REGISTER, addr[5]); | |
return this; | |
} | |
/*************************************************************************** | |
* setSourceIP | |
* Returns: this | |
* Parameters: | |
* addr - an array of 4 integers with the IP address for the | |
* source hardware | |
**************************************************************************/ | |
function setSourceIP(addr) { | |
writeReg(W5500_SOURCE_IP_ADDR_0, W5500_COMMON_REGISTER, addr[0]); | |
writeReg(W5500_SOURCE_IP_ADDR_1, W5500_COMMON_REGISTER, addr[1]); | |
writeReg(W5500_SOURCE_IP_ADDR_2, W5500_COMMON_REGISTER, addr[2]); | |
writeReg(W5500_SOURCE_IP_ADDR_3, W5500_COMMON_REGISTER, addr[3]); | |
return this; | |
} | |
/*************************************************************************** | |
* setSourceIP | |
* Returns: this | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
* addr - an array of 2 integers with the port for the | |
* source hardware | |
* (ex: for port 4242, addr = [0x10, 0x92]) | |
**************************************************************************/ | |
function setSourcePort(socket, port) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
writeReg(W5500_SOCKET_SOURCE_PORT_0, bsb, port[0]); | |
writeReg(W5500_SOCKET_SOURCE_PORT_1, bsb, port[1]); | |
return this; | |
} | |
/*************************************************************************** | |
* setDestHWAddr | |
* Returns: this | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
* addr - an array of 6 integers with the mac address for the | |
* destination hardware | |
**************************************************************************/ | |
function setDestHWAddr(socket, addr) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
writeReg(W5500_SOCKET_DEST_HW_ADDR_0, bsb, addr[0]); | |
writeReg(W5500_SOCKET_DEST_HW_ADDR_1, bsb, addr[1]); | |
writeReg(W5500_SOCKET_DEST_HW_ADDR_2, bsb, addr[2]); | |
writeReg(W5500_SOCKET_DEST_HW_ADDR_3, bsb, addr[3]); | |
writeReg(W5500_SOCKET_DEST_HW_ADDR_4, bsb, addr[4]); | |
writeReg(W5500_SOCKET_DEST_HW_ADDR_5, bsb, addr[5]); | |
return this; | |
} | |
/*************************************************************************** | |
* setDestIP | |
* Returns: this | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
* addr - an array of 4 integers with the IP address for the | |
* destination hardware | |
**************************************************************************/ | |
function setDestIP(socket, addr) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
writeReg(W5500_SOCKET_DEST_IP_ADDR_0, bsb, addr[0]); | |
writeReg(W5500_SOCKET_DEST_IP_ADDR_1, bsb, addr[1]); | |
writeReg(W5500_SOCKET_DEST_IP_ADDR_2, bsb, addr[2]); | |
writeReg(W5500_SOCKET_DEST_IP_ADDR_3, bsb, addr[3]); | |
return this; | |
} | |
/*************************************************************************** | |
* setDestPort | |
* Returns: this | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
* addr - an array of 2 integers with the port for the | |
* destination hardware | |
* (ex: for port 4242, addr = [0x10, 0x92]) | |
**************************************************************************/ | |
function setDestPort(socket, port) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
writeReg(W5500_SOCKET_DEST_PORT_0, bsb, port[0]); | |
writeReg(W5500_SOCKET_DEST_PORT_1, bsb, port[1]); | |
return this; | |
} | |
/*************************************************************************** | |
* setRxReadPointer | |
* Returns: this | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
* value - new RX read pointer value | |
**************************************************************************/ | |
function setRxReadPointer(socket, value) { | |
local rx_pointer_r1 = (value & 0xFF00) >> 8; | |
local rx_pointer_r2 = value & 0x00FF; | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
writeReg(W5500_SOCKET_RX_RP_R1, bsb, rx_pointer_r1); | |
writeReg(W5500_SOCKET_RX_RP_R2, bsb, rx_pointer_r2); | |
return this; | |
} | |
/*************************************************************************** | |
* setTxWritePointer | |
* Returns: this | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
* value - new TX write pointer value | |
**************************************************************************/ | |
function setTxWritePointer(socket, value) { | |
local tx_pointer_r1 = (value & 0xFF00) >> 8; | |
local tx_pointer_r2 = value & 0x00FF; | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
writeReg(W5500_SOCKET_TX_WP_R1, bsb, tx_pointer_r1); | |
writeReg(W5500_SOCKET_TX_WP_R2, bsb, tx_pointer_r2); | |
return this; | |
} | |
/*************************************************************************** | |
* getPYHConfigReg | |
* Returns: register value of Phy config | |
* Parameters: none | |
**************************************************************************/ | |
function getPYHConfigReg() { | |
return readReg(W5500_PHY_CONFIG, W5500_COMMON_REGISTER); | |
} | |
/*************************************************************************** | |
* getSocketStatus | |
* Returns: integer with the connection status for the socket passed in | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function getSocketStatus(socket) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
return readReg(W5500_SOCKET_STATUS, bsb); | |
} | |
/*************************************************************************** | |
* getRxReadPointer | |
* Returns: value of read pointer | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function getRxReadPointer(socket) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
local rx_pointer_pt1 = readReg(W5500_SOCKET_RX_RP_R1, bsb) << 8; | |
local rx_pointer_pt2 = readReg(W5500_SOCKET_RX_RP_R2, bsb); | |
return rx_pointer_pt1 | rx_pointer_pt2; | |
} | |
/*************************************************************************** | |
* getTxReadPointer | |
* Returns: value of read pointer | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function getTxReadPointer(socket) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
local tx_pointer_pt1 = readReg(W5500_SOCKET_TX_RP_R1, bsb) << 8; | |
local tx_pointer_pt2 = readReg(W5500_SOCKET_TX_RP_R2, bsb); | |
return tx_pointer_pt1 | tx_pointer_pt2; | |
} | |
/*************************************************************************** | |
* getRxDataSize | |
* Returns: value of received data size register | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function getRxDataSize(socket) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
local rx_pt1 = readReg(W5500_SOCKET_RX_SIZE_R1, bsb) << 8; | |
local rx_pt2 = readReg(W5500_SOCKET_RX_SIZE_R2, bsb); | |
return rx_pt1 | rx_pt2; | |
} | |
/*************************************************************************** | |
* getFreeTxDataSize | |
* Returns: value of TX data free size register | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function getFreeTxDataSize(socket) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
local tx_fd_pt1 = readReg(W5500_SOCKET_TX_SIZE_R1, bsb) << 8; | |
local tx_fd_pt2 = readReg(W5500_SOCKET_TX_SIZE_R2, bsb); | |
return tx_fd_pt1 | tx_fd_pt2; | |
} | |
/*************************************************************************** | |
* getSocketRXBufferSize | |
* Returns: value of RX data buffer size register | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function getSocketRXBufferSize(socket) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
return readReg(W5500_SOCKET_RX_BUFFER_SIZE, bsb); | |
} | |
/*************************************************************************** | |
* getSocketTXBufferSize | |
* Returns: value of TX data buffer size register | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function getSocketTXBufferSize(socket) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
return readReg(W5500_SOCKET_TX_BUFFER_SIZE, bsb); | |
} | |
/*************************************************************************** | |
* getChipVersion | |
* Returns: chip version (should be 0x04 for the W5500) | |
* Parameters: none | |
**************************************************************************/ | |
function getChipVersion() { | |
server.log("getting chip version"); | |
return readReg(W5500_CHIP_VERSION, W5500_COMMON_REGISTER); | |
} | |
/*************************************************************************** | |
* getTotalSupportedSockets | |
* Returns: number of sockets the driver code currently supports | |
* Parameters: none | |
**************************************************************************/ | |
function getTotalSupportedSockets() { | |
return TOTAL_SUPPORTED_SOCKETS; | |
} | |
/*************************************************************************** | |
* getMemoryInfo | |
* Returns: table with memory maximums and supported memory block sizes | |
* Parameters: none | |
**************************************************************************/ | |
function getMemoryInfo() { | |
// mem_block_sizes - an array with supported values highest to lowest | |
return {"tx_max" : MAX_TX_MEM_BUFFER, "rx_max": MAX_RX_MEM_BUFFER, "mem_block_sizes" : [16, 8, 4, 2, 1, 0]} | |
} | |
// TRANSMISSION FUNCTIONS | |
// --------------------------------------------- | |
/*************************************************************************** | |
* sendSocketCommand | |
* Returns: this | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
* command - select command using SOCKET_COMMANDS constant | |
**************************************************************************/ | |
function sendSocketCommand(socket, command) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
writeReg(W5500_SOCKET_COMMAND, bsb, command); | |
return this; | |
} | |
/*************************************************************************** | |
* readRxData | |
* Returns: data from received data register | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function readRxData(socket) { | |
// get the received data size | |
local dataSize = getRxDataSize(socket); | |
// TODO: check dataSize is within range of avail memory - throw error | |
// select RX memory | |
local cntl_byte = getSocketRXBufferSize(socket); | |
// Get offset address | |
local src_ptr = getRxReadPointer(socket); | |
// get Block select bit for RX buffer | |
local bsb = _getSocketRXBufferBlockSelectBit(socket); | |
// use cntl_byte and src_ptr to get addr?? | |
// read transmitted data here | |
local data = _readData(src_ptr, bsb, dataSize); | |
// increase Sn_RX_RD as length of len | |
src_ptr += dataSize; | |
setRxReadPointer(socket, src_ptr); | |
// set RECV command | |
sendSocketCommand(socket, W5500_SOCKET_RECEIVE); | |
return data; | |
} | |
/*************************************************************************** | |
* sendTxData | |
* Returns: length of data to transmit | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
* transmitData - data to be sent | |
**************************************************************************/ | |
function sendTxData(socket, transmitData) { | |
local tx_length = transmitData.len(); | |
// check transmission data size | |
if (tx_length > socketMemory.tx[socket]) { | |
server.error("Transmit data larger than socket transmit buffer."); | |
return | |
// TODO: if data is too large chunk and send | |
} | |
// select TX memory | |
local cntl_byte = getSocketTXBufferSize(socket); | |
// Get offset address | |
local dst_ptr = getTxReadPointer(socket); //Sn_TX_RD; | |
// get Block select bit for RX buffer | |
local bsb = _getSocketTXBufferBlockSelectBit(socket); | |
// write transmit data | |
_writeData(dst_ptr, bsb, transmitData); | |
// increase Sn_TX_WR as length of send_size | |
dst_ptr += tx_length; // adjust write pointer get first?? | |
setTxWritePointer(socket, dst_ptr); | |
// set SEND command | |
sendSocketCommand(socket, W5500_SOCKET_SEND); | |
return tx_length; | |
} | |
// INTERRUPT FUNCTIONS | |
// --------------------------------------------- | |
/*************************************************************************** | |
* setInterrupt | |
* Returns: this | |
* Parameters: | |
* type - select interrupt type using interrupt type | |
* constants or-ed together | |
**************************************************************************/ | |
function setInterrupt(type) { | |
writeReg(W5500_INTERRUPT_MASK, W5500_COMMON_REGISTER, type); | |
return this; | |
} | |
/*************************************************************************** | |
* clearInterrupt | |
* Returns: this | |
* Parameters: | |
* type(optional) - clear specified interrupt type | |
* if nothing passed in clears all interrupts | |
**************************************************************************/ | |
function clearInterrupt(type = 0xF0) { | |
writeReg(W5500_INTERRUPT, W5500_COMMON_REGISTER, type); | |
return this; | |
} | |
/*************************************************************************** | |
* setSocketInterrupt | |
* Returns: this | |
* Parameters: | |
* socketInt - select the sockets to enable interrupts on using | |
* SOCKET INTERRUPTS constants or-ed together | |
* type(optional) - select SOCKET INTERRUPT TYPES using constants | |
* or-ed together, if type not passed in all type interrupts | |
* will be cleared. | |
**************************************************************************/ | |
function setSocketInterrupt(socketInt, type = 0x1F) { | |
writeReg(W5500_SOCKET_INTERRUPT_MASK, W5500_COMMON_REGISTER, socketInt); | |
// default enables all socket interrupt types | |
writeReg(W5500_SOCKET_N_INTERRUPT_MASK, W5500_COMMON_REGISTER, type); | |
return this; | |
} | |
/*************************************************************************** | |
* clearSocketInterrupt | |
* Returns: this | |
* Parameters: | |
* socket : socket (selected by integer) to clear interrupt on | |
* type(optional) - clear specified interrupt type | |
* if nothing passed in clears all interrupts | |
**************************************************************************/ | |
function clearSocketInterrupt(socket, type = 0x1F) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
writeReg(W5500_SOCKET_N_INTERRUPT, bsb, type); | |
return this; | |
} | |
/*************************************************************************** | |
* getInterruptStatus | |
* Returns: interrupt status table | |
* Parameters: none | |
**************************************************************************/ | |
function getInterruptStatus() { | |
local status = readReg(W5500_INTERRUPT, W5500_COMMON_REGISTER); | |
local intStatus = { | |
"CONFLICT" : status & W5500_CONFLICT_INT_TYPE ? true : false, | |
"UNREACH" : status & W5500_UNREACH_INT_TYPE ? true : false, | |
"PPPoE" : status & W5500_PPPoE_INT_TYPE ? true : false, | |
"MAGIC_PACKET" : status & W5500_MAGIC_PACKET_TYPE ? true : false, | |
"REGISTER_VALUE" : status | |
}; | |
return intStatus; | |
} | |
/*************************************************************************** | |
* getSocketInterruptStatus | |
* Returns: interrupt status table | |
* Parameters: none | |
**************************************************************************/ | |
function getSocketInterruptStatus() { | |
local status = readReg(W5500_SOCKET_INTERRUPT, W5500_COMMON_REGISTER); | |
local intStatus = { | |
"SOCKET_7" : status & W5500_S7_INTERRUPT ? true : false, | |
"SOCKET_6" : status & W5500_S6_INTERRUPT ? true : false, | |
"SOCKET_5" : status & W5500_S5_INTERRUPT ? true : false, | |
"SOCKET_4" : status & W5500_S4_INTERRUPT ? true : false, | |
"SOCKET_3" : status & W5500_S3_INTERRUPT ? true : false, | |
"SOCKET_2" : status & W5500_S2_INTERRUPT ? true : false, | |
"SOCKET_1" : status & W5500_S1_INTERRUPT ? true : false, | |
"SOCKET_0" : status & W5500_S0_INTERRUPT ? true : false, | |
"REGISTER_VALUE" : status | |
}; | |
return intStatus; | |
} | |
/*************************************************************************** | |
* getSocketInterruptTypeStatus | |
* Returns: socket interrupt status table | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function getSocketInterruptTypeStatus(socket) { | |
local bsb = _getSocketRegBlockSelectBit(socket); | |
local status = readReg(W5500_SOCKET_N_INTERRUPT, bsb); | |
local intStatus = { | |
"SEND_COMPLETE" : status & W5500_SEND_COMPLETE_INT_TYPE ? true : false, | |
"TIMEOUT" : status & W5500_TIMEOUT_INT_TYPE ? true : false, | |
"DATA_RECEIVED" : status & W5500_DATA_RECEIVED_INT_TYPE ? true : false, | |
"DISCONNECTED" : status & W5500_DISCONNECTED_INT_TYPE ? true : false, | |
"CONNECTED" : status & W5500_CONNECTED_INT_TYPE ? true : false, | |
"REGISTER_VALUE" : status | |
}; | |
return intStatus; | |
} | |
// SPI FUNCTIONS | |
// --------------------------------------------- | |
/*************************************************************************** | |
* readReg | |
* Returns: data stored at the specified register | |
* Parameters: | |
* reg - register to read | |
**************************************************************************/ | |
function readReg(addr, bsb) { | |
local b = blob(); | |
local cp = bsb | W5500_READ_COMMAND | W5500_VARIABLE_DATA_LENGTH; | |
local res = blob(); | |
(_cs) ? _cs.write(0) : _spi.chipselect(1); | |
b.writen(addr >> 8, 'b'); | |
b.writen(addr & 0xFF, 'b'); | |
b.writen(cp, 'b'); | |
b.writen(0x00, 'b'); | |
res = _spi.writeread(b); | |
(_cs) ? _cs.write(1) : _spi.chipselect(0); | |
return res[3]; | |
} | |
/*************************************************************************** | |
* writeReg | |
* Returns: null | |
* Parameters: | |
* reg - register to write to | |
* value - data to write to register | |
**************************************************************************/ | |
function writeReg(addr, bsb, value) { | |
local b = blob(); | |
local cp = bsb | W5500_WRITE_COMMAND | W5500_VARIABLE_DATA_LENGTH; | |
(_cs) ? _cs.write(0) : _spi.chipselect(1); | |
b.writen(addr >> 8, 'b'); | |
b.writen(addr & 0xFF, 'b'); | |
b.writen(cp, 'b'); | |
b.writen(value, 'b'); | |
_spi.write(b); | |
(_cs) ? _cs.write(1) : _spi.chipselect(0); | |
} | |
// RESET FUNCTION | |
// --------------------------------------------- | |
/*************************************************************************** | |
* reset, note this is blocking for 0.2s | |
* Returns: this | |
* Parameters: | |
* sw(optional) - boolean if true forces a software reset | |
* Note: datasheet for W5500 states that software reset is | |
* unreliable - don't use | |
**************************************************************************/ | |
function reset(sw = false) { | |
if (sw || _resetPin == null) { | |
setMode(W5500_SW_RESET); | |
imp.sleep(0.2); | |
} else { | |
_resetPin.write(0); | |
imp.sleep(0.001); // hold at least 500us after assert low | |
_resetPin.write(1); | |
imp.sleep(0.2); // wait at least 150ms before configuring | |
} | |
_setMemDefaults(); | |
return this; | |
} | |
// PRIVATE FUNCTIONS | |
// --------------------------------------------- | |
/*************************************************************************** | |
* _getSocketRegBlockSelectBit | |
* Returns: the socket register Control Phase Block Select Bit for the socket passed in | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function _getSocketRegBlockSelectBit(socket) { | |
local bsb = null; | |
switch(socket) { | |
case 0: | |
bsb = W5500_S0_REGISTER; | |
break; | |
case 1: | |
bsb = W5500_S1_REGISTER; | |
break; | |
case 2: | |
bsb = W5500_S2_REGISTER; | |
break; | |
case 3: | |
bsb = W5500_S3_REGISTER; | |
break; | |
} | |
return bsb; | |
} | |
/*************************************************************************** | |
* _getSocketRXBufferBlockSelectBit | |
* Returns: the socket RX buffer Control Phase Block Select Bit for the socket passed in | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function _getSocketRXBufferBlockSelectBit(socket) { | |
local bsb = null; | |
switch(socket) { | |
case 0: | |
bsb = W5500_S0_RX_BUFFER; | |
break; | |
case 1: | |
bsb = W5500_S1_RX_BUFFER; | |
break; | |
case 2: | |
bsb = W5500_S2_RX_BUFFER; | |
break; | |
case 3: | |
bsb = W5500_S3_RX_BUFFER; | |
break; | |
} | |
return bsb; | |
} | |
/*************************************************************************** | |
* _getSocketRXBufferBlockSelectBit | |
* Returns: the socket TX buffer Control Phase Block Select Bit for the socket passed in | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function _getSocketTXBufferBlockSelectBit(socket) { | |
local bsb = null; | |
switch(socket) { | |
case 0: | |
bsb = W5500_S0_TX_BUFFER; | |
break; | |
case 1: | |
bsb = W5500_S1_TX_BUFFER; | |
break; | |
case 2: | |
bsb = W5500_S2_TX_BUFFER; | |
break; | |
case 3: | |
bsb = W5500_S3_TX_BUFFER; | |
break; | |
} | |
return bsb; | |
} | |
// MEMORY FUNCTIONS | |
/*************************************************************************** | |
* _setMemDefaults, sets locally stored default socket memory info | |
* Returns: null | |
* Parameters: none | |
**************************************************************************/ | |
function _setMemDefaults() { | |
socketMemory = { "rx" : [2048, 2048, 2048, 2048], | |
"tx" : [2048, 2048, 2048, 2048] | |
} | |
} | |
// TRANSMITION FUNCTIONS | |
/*************************************************************************** | |
* _writeData, writes data to transmit memory buffer | |
* Returns: size of data written | |
* Parameters: | |
* addr - offset address to start the data write | |
* bsb - socket tx buffer block select bit | |
* data - data to be written | |
**************************************************************************/ | |
function _writeData(addr, bsb, data) { | |
foreach (item in data) { | |
writeReg(addr, bsb, item); | |
addr++; | |
} | |
return data.len(); | |
} | |
/*************************************************************************** | |
* _readData | |
* Returns: blob containing data from memory buffer | |
* Parameters: | |
* addr - offset address to start the read | |
* bsb - block select bit for the socket rx buffer | |
* size - size of data to be written | |
**************************************************************************/ | |
function _readData(addr, bsb, size) { | |
local b = blob(); | |
while (size != 0) { | |
b.writen(readReg(addr, bsb), 'b'); | |
addr++; | |
size--; | |
} | |
return b | |
} | |
// DEBUG/LOGGING FUNCTIONS | |
function _logGatewayIP() { | |
server.log("----------------------------------") | |
server.log( format("Gateway IP: %i.%i.%i.%i", readReg(W5500_GATEWAY_ADDR_0, W5500_COMMON_REGISTER), readReg(W5500_GATEWAY_ADDR_1, W5500_COMMON_REGISTER), readReg(W5500_GATEWAY_ADDR_2, W5500_COMMON_REGISTER), readReg(W5500_GATEWAY_ADDR_3, W5500_COMMON_REGISTER)) ) | |
server.log("----------------------------------") | |
} | |
function _logSourceAddr() { | |
server.log("----------------------------------") | |
server.log( format("Source Mac Addr: %02X %02X %02X %02X %02X %02X", readReg(W5500_SOURCE_HW_ADDR_0, W5500_COMMON_REGISTER), readReg(W5500_SOURCE_HW_ADDR_1, W5500_COMMON_REGISTER), readReg(W5500_SOURCE_HW_ADDR_2, W5500_COMMON_REGISTER), readReg(W5500_SOURCE_HW_ADDR_3, W5500_COMMON_REGISTER), readReg(W5500_SOURCE_HW_ADDR_4, W5500_COMMON_REGISTER), readReg(W5500_SOURCE_HW_ADDR_5, W5500_COMMON_REGISTER)) ) | |
server.log("----------------------------------") | |
} | |
function _logSubnet() { | |
server.log("----------------------------------") | |
server.log( format("Subnet Addr: %i.%i.%i.%i", readReg(W5500_SUBNET_MASK_ADDR_0, W5500_COMMON_REGISTER), readReg(W5500_SUBNET_MASK_ADDR_1, W5500_COMMON_REGISTER), readReg(W5500_SUBNET_MASK_ADDR_2, W5500_COMMON_REGISTER), readReg(W5500_SUBNET_MASK_ADDR_3, W5500_COMMON_REGISTER)) ) | |
server.log("----------------------------------") | |
} | |
function _logSourceIP() { | |
server.log("----------------------------------") | |
server.log( format("Source IP: %i.%i.%i.%i", readReg(W5500_SOURCE_IP_ADDR_0, W5500_COMMON_REGISTER), readReg(W5500_SOURCE_IP_ADDR_1, W5500_COMMON_REGISTER), readReg(W5500_SOURCE_IP_ADDR_2, W5500_COMMON_REGISTER), readReg(W5500_SOURCE_IP_ADDR_3, W5500_COMMON_REGISTER)) ) | |
server.log("----------------------------------") | |
} | |
function _logS0SourcePort() { | |
local bsb = _getSocketRegBlockSelectBit(0); | |
local p1 = readReg(W5500_SOCKET_SOURCE_PORT_0, bsb); | |
local p2 = readReg(W5500_SOCKET_SOURCE_PORT_1, bsb); | |
local port = (p1 * 256) + p2; | |
server.log("----------------------------------") | |
server.log( format("Source Port: %i", port) ) | |
server.log("----------------------------------") | |
} | |
function _logS0DestPort() { | |
local bsb = _getSocketRegBlockSelectBit(0); | |
local p1 = readReg(W5500_SOCKET_DEST_PORT_0, bsb); | |
local p2 = readReg(W5500_SOCKET_DEST_PORT_1, bsb); | |
local port = (p1 * 256) + p2; | |
server.log("----------------------------------") | |
server.log( format("Destination Port: %i", port) ) | |
server.log("----------------------------------") | |
} | |
function _logS0DestIP() { | |
local bsb = _getSocketRegBlockSelectBit(0); | |
server.log("----------------------------------") | |
server.log( format("Destination IP: %i.%i.%i.%i", readReg(W5500_SOCKET_DEST_IP_ADDR_0, bsb), readReg(W5500_SOCKET_DEST_IP_ADDR_1, bsb), readReg(W5500_SOCKET_DEST_IP_ADDR_2, bsb), readReg(W5500_SOCKET_DEST_IP_ADDR_3, bsb)) ) | |
server.log("----------------------------------") | |
} | |
} | |
class W5500.API { | |
_wiz = null; | |
_interruptPin = null; | |
timer = null; | |
_totalSockets = null; | |
_avaiableConnections = null; // number of sockets available | |
_connections = null; | |
_socketConnectionState = null; | |
_cleanupCounter = null; | |
/*************************************************************************** | |
* Constructor | |
* Returns: null | |
* Parameters: | |
* spi - configured spi bus, chip supports spi mode 0 or 3 | |
* interruptPin - inerrupt pin | |
* cs(optional) - chip select pin, pass in if not using imp005 | |
* reset(optional) - reset pin | |
**************************************************************************/ | |
constructor(spi, interruptPin, csPin = null, resetPin = null) { | |
local imp005 = ("spi0" in hardware); | |
if (csPin != null) { | |
csPin.configure(DIGITAL_OUT, 1); | |
} else if (!imp005) { | |
throw "Error: You must pass in a chip select pin." | |
return; | |
} | |
if (resetPin) resetPin.configure(DIGITAL_OUT, 1); | |
_wiz = W5500.Driver(spi, csPin, resetPin); | |
_createConnectionStateArray(); | |
_cleanupCounter = 0; | |
_cleanup(); // close stale connections | |
_cleanupWatchdog(function() { | |
// Reset chip to default state, blocks for 0.2s | |
// Note: Datasheet states that W5500 software reset | |
// is not reliable, use hardware reset. | |
reset(); | |
// Configure number of connections (sets up default memory and interrupts) | |
_connections = {}; | |
setNumberOfAvailbleConnections(1); | |
// Configure interrupts | |
_setDefaultInterrupts(); | |
_clearAllInterrupts(); | |
_interruptPin = interruptPin.configure(DIGITAL_IN_PULLUP, _interruptHandler.bindenv(this)); | |
}) | |
} | |
// SETUP FUNCTIONS | |
// --------------------------------------------- | |
/*************************************************************************** | |
* configureNetworkSettings | |
* Returns: this | |
* Parameters: | |
* networkSettings - table with keys: gatewayIP, sourceAddr, subnet, sourceIP | |
* values are arrays of integers | |
**************************************************************************/ | |
function configureNetworkSettings(networkSettings) { | |
if ("gatewayIP" in networkSettings) _wiz.setGatewayAddr(networkSettings.gatewayIP); | |
if ("sourceAddr" in networkSettings) _wiz.setSourceHWAddr(networkSettings.sourceAddr); | |
if ("subnet" in networkSettings) _wiz.setSubnet(networkSettings.subnet); | |
if ("sourceIP" in networkSettings) _wiz.setSourceIP(networkSettings.sourceIP); | |
return this; | |
} | |
/*************************************************************************** | |
* setReceiveCallback | |
* Returns: this | |
* Parameters: | |
* connection - connection instance to set callback on | |
* cb - function to be called when data is received | |
**************************************************************************/ | |
function setReceiveCallback(connection, cb) { | |
connection.setReceiveHandler(cb); | |
return this; | |
} | |
/*************************************************************************** | |
* setDisconnectCallback | |
* Returns: this | |
* Parameters: | |
* connection - connection instance to set callback on | |
* cb - function to be called when disconnect interrupt triggered | |
**************************************************************************/ | |
function setDisconnectCallback(connection, cb) { | |
connection.setDisconnectHandler(cb); | |
return this; | |
} | |
/*************************************************************************** | |
* setNumConnections - configures interrupts and memory for each connection | |
* Returns: number of actual connections configured | |
* Parameters: | |
* numConnections - number of desired connections | |
**************************************************************************/ | |
function setNumberOfAvailbleConnections(numConnections) { | |
// limit number of connections to what driver can support | |
if (numConnections < 1) numConnections = 1; | |
if (numConnections > _totalSockets ) numConnections = _totalSockets; | |
// calculate max memory for number of connections | |
local memoryInfo = _wiz.getMemoryInfo(); | |
local tx_mem = _getMaxMemValue(numConnections, memoryInfo.tx_max, memoryInfo.mem_block_sizes); | |
local rx_mem = _getMaxMemValue(numConnections, memoryInfo.rx_max, memoryInfo.mem_block_sizes); | |
// Enable interrupt for each connection | |
// Set max equal memory accross connections | |
switch (numConnections) { | |
case 1: | |
_avaiableConnections = [0]; | |
_wiz.setSocketInterrupt(W5500_S0_INTERRUPT); | |
_configureSocketMemory([tx_mem, 0, 0, 0], [rx_mem, 0, 0, 0]); | |
break; | |
case 2: | |
_avaiableConnections = [1, 0]; | |
_wiz.setSocketInterrupt(W5500_S0_INTERRUPT | W5500_S1_INTERRUPT); | |
_configureSocketMemory([tx_mem, tx_mem, 0, 0], [rx_mem, rx_mem, 0, 0]); | |
break; | |
case 3: | |
_avaiableConnections = [2, 1, 0]; | |
_wiz.setSocketInterrupt(W5500_S0_INTERRUPT | W5500_S1_INTERRUPT | W5500_S2_INTERRUPT); | |
_configureSocketMemory([tx_mem, tx_mem, tx_mem, 0], [rx_mem, rx_mem, rx_mem, 0]); | |
break; | |
case 4: | |
_avaiableConnections = [3, 2, 1, 0]; | |
_wiz.setSocketInterrupt(W5500_S0_INTERRUPT | W5500_S1_INTERRUPT | W5500_S2_INTERRUPT | W5500_S3_INTERRUPT); | |
_configureSocketMemory([tx_mem, tx_mem, tx_mem, tx_mem], [rx_mem, rx_mem, rx_mem, rx_mem]); | |
break; | |
} | |
return numConnections; | |
} | |
// CONNECTION FUNCTIONS | |
// --------------------------------------------- | |
/*************************************************************************** | |
* openConnection | |
* Returns: connection instance | |
* Parameters: | |
* connectionSettings - table with keys: socket, destIP, destPort, | |
* mode(optional - only TCP supported) | |
* cb(optional) - function to be called when connection successfully | |
* established or a timeout has occurred | |
**************************************************************************/ | |
function openConnection(connectionSettings, cb = null) { | |
// check for required parameters | |
if (_avaiableConnections.len() < 1) throw "Cannot open a connection. All connection sockets in use."; | |
if (!("destIP" in connectionSettings)) throw "Cannot open a connection. Missing: Destination IP Address."; | |
if (!("destPort" in connectionSettings)) throw "Cannot open a connection. Missing: Destination Port."; | |
local socket = _avaiableConnections.pop(); | |
connectionSettings.sourcePort <- _returnRandomPort(1024, 65535); // creates a random port between 1024-65535 | |
if ("socketMode" in connectionSettings) { | |
_wiz.setSocketMode(socket, connectionSettings.socketMode); | |
} else { | |
_wiz.setSocketMode(socket, W5500_SOCKET_MODE_TCP); | |
} | |
// Open socket connection | |
_socketConnectionState[socket] = "CONNECTING"; | |
_wiz.setSourcePort(socket, connectionSettings.sourcePort); | |
_wiz.sendSocketCommand(socket, W5500_SOCKET_OPEN); | |
// Connect | |
_wiz.setDestIP(socket, connectionSettings.destIP); | |
_wiz.setDestPort(socket, connectionSettings.destPort); | |
imp.sleep(1); | |
_wiz.sendSocketCommand(socket, W5500_SOCKET_CONNECT); | |
// Create connection object & handler | |
local connection = W5500.Connection(socket, _socketConnectionState[socket], connectionSettings); | |
_connections[socket] <- connection; | |
if (cb) connection.setConnectHandler(cb); | |
return connection; | |
} | |
/*************************************************************************** | |
* closeConnection | |
* Returns: this | |
* Parameters: | |
* connection - connection instance to close the connection on | |
**************************************************************************/ | |
function closeConnection(connection) { | |
_wiz.sendSocketCommand(connection.socket, W5500_SOCKET_DISCONNECT); | |
_updateConnectionState(connection, "DISCONNECTING"); | |
return this; | |
} | |
// TRANSMISSION FUNCTIONS | |
// --------------------------------------------- | |
/*************************************************************************** | |
* transmit | |
* Returns: this | |
* Parameters: | |
* connection - connection instance to transmit data on | |
* transmitData - array/blob of data to transmit | |
* cb(optional) - function to be called when data successfully | |
* sent or timeout has occurred | |
**************************************************************************/ | |
function transmit(connection, transmitData, cb = null) { | |
local socket = connection.socket; | |
local receiveHandler = connection.getHandler("receive"); | |
if (_socketConnectionState[socket] == "ESTABLISHED") { | |
connection.setTransmitHandler(cb); | |
if (dataWaiting(socket) && receiveHandler) { | |
receiveHandler(null, socket, _wiz.readRxData(socket)); | |
} | |
_wiz.sendTxData(socket, transmitData); | |
} else { | |
if (cb) { | |
imp.wakeup(0, function() { | |
cb("Error: Connection not established.", connection); | |
}.bindenv(this)); | |
} | |
} | |
return this; | |
} | |
/*************************************************************************** | |
* receive | |
* Returns: this | |
* Parameters: | |
* connection - connection instance to check for received data on | |
* cb(optional) - callback to pass receive data to | |
* (note: if callback is passed in it will superceede | |
* the callback set by setReceiveCallback, and will be | |
* used only for during this check for data) | |
**************************************************************************/ | |
function receive(connection, cb = null) { | |
local socket = connection.socket; | |
local receiveHandler = connection.getHandler("receive"); | |
if (_socketConnectionState[socket] == "ESTABLISHED") { | |
if ( dataWaiting(socket) ) { | |
if(cb) { | |
imp.wakeup(0, function() { | |
cb(null, socket, _wiz.readRxData(socket)); | |
}.bindenv(this)); | |
} else if (receiveHandler) { | |
imp.wakeup(0, function() { | |
receiveHandler(null, socket, _wiz.readRxData(socket)); | |
}.bindenv(this)); | |
} | |
} | |
} else { | |
if (cb) { | |
imp.wakeup(0, function() { | |
cb("Error: Connection not established.", connection, null); | |
}.bindenv(this)); | |
} else if (receiveHandler) { | |
imp.wakeup(0, function() { | |
receiveHandler("Error: Connection not established.", connection, null); | |
}.bindenv(this)); | |
} | |
} | |
return this; | |
} | |
// HELPER FUNCTIONS | |
// --------------------------------------------- | |
/*************************************************************************** | |
* reset, note this is blocking for 0.2s | |
* Returns: this | |
* Parameters: | |
* sw(optional) - boolean if true forces a software reset | |
* Note: Datasheet states that SW reset should not be used | |
* on the W5500. | |
**************************************************************************/ | |
function reset(sw = false) { | |
_wiz.reset(sw); | |
} | |
/*************************************************************************** | |
* dataWaiting | |
* Returns: boolean | |
* Parameters: | |
* socket - connection socket | |
**************************************************************************/ | |
function dataWaiting(socket) { | |
return (_wiz.getRxDataSize(socket) == 0x00) ? false : true; | |
} | |
/*************************************************************************** | |
* connectionEstablished | |
* Returns: boolean | |
* Parameters: | |
* socket - connection socket | |
**************************************************************************/ | |
function connectionEstablished(socket) { | |
return (_wiz.getSocketStatus(socket) == W5500_SOCKET_STATUS_ESTABLISHED) ? true : false; | |
} | |
// PRIVATE FUNCTIONS | |
// --------------------------------------------- | |
/*************************************************************************** | |
* _setDefaultInterrupts: conflict | |
* Returns: this | |
* Parameters: NONE | |
**************************************************************************/ | |
function _setDefaultInterrupts() { | |
_wiz.setInterrupt(W5500_CONFLICT_INT_TYPE); | |
return this; | |
} | |
/*************************************************************************** | |
* _getMaxMemValue | |
* Returns: max memory value | |
* Parameters: | |
* numValues - number of memory slots | |
* max - max memory available | |
* blockSizes - array of supported memory sizes | |
**************************************************************************/ | |
function _getMaxMemValue(numValues, max, blockSizes) { | |
// make sure memory values are in desending order | |
blockSizes.sort(); | |
blockSizes.reverse(); | |
local memory = max / numValues; | |
foreach (value in blockSizes) { | |
if (memory >= value) { | |
memory = value; | |
break; | |
} | |
} | |
return memory; | |
} | |
/*************************************************************************** | |
* _configureSocketMemory | |
* Returns: this | |
* Parameters: | |
* txMem - an array of four integers with the desired transmit memory | |
* allotment for each socket | |
* rxMem - an array of four integers with the desired receive memory | |
* allotment for each socket | |
**************************************************************************/ | |
function _configureSocketMemory(txMem, rxMem) { | |
_wiz.setMemory(txMem, "tx"); | |
_wiz.setMemory(rxMem, "rx"); | |
return this; | |
} | |
/*************************************************************************** | |
* _returnRandomPort | |
* Returns: an array with a random port between min and max | |
* Parameters: | |
* min - lowest possible port number | |
* max - highest possible port number | |
**************************************************************************/ | |
function _returnRandomPort(min, max) { | |
local port = (1.0 * math.rand() / RAND_MAX) * (max + 1 - min); | |
port = port.tointeger() + min; | |
local p1 = port >> 8; | |
local p2 = port & 0xFF; | |
return [p1, p2]; | |
} | |
/*************************************************************************** | |
* _createConnectionStateArray, sets local connection state for all sockets | |
* to null | |
* Returns: this | |
* Parameters: none | |
**************************************************************************/ | |
function _createConnectionStateArray() { | |
_socketConnectionState = []; | |
_totalSockets = _wiz.getTotalSupportedSockets(); | |
for (local socket = 0; socket < _totalSockets ; socket++) { | |
_socketConnectionState.push(null); | |
} | |
return this; | |
} | |
/*************************************************************************** | |
* _cleanup, if any sockets have open connections it disconnects them | |
* Returns: null | |
* Parameters: none | |
**************************************************************************/ | |
function _cleanup() { | |
// close any sockets that have open connections | |
for (local socket = 0; socket < _totalSockets ; socket++) { | |
if( connectionEstablished(socket) ) { | |
_wiz.sendSocketCommand(socket, W5500_SOCKET_DISCONNECT); | |
imp.sleep(0.01); | |
_closeSocket(socket); | |
} else { | |
_socketConnectionState[socket] = "CLOSED"; | |
_cleanupCounter++; | |
} | |
} | |
} | |
/*************************************************************************** | |
* _closeSocket, confirms socket has been successfully disconnected | |
* then closes(will loop until disconnect successful) | |
* Returns: null | |
* Parameters: | |
* socket - connection socket to close connection on | |
**************************************************************************/ | |
function _closeSocket(socket) { | |
if ( _wiz.getSocketStatus(socket) != W5500_SOCKET_STATUS_CLOSED) { | |
imp.sleep(0.01); | |
_closeSocket(socket); | |
} else { | |
_wiz.sendSocketCommand(socket, W5500_SOCKET_CLOSE); | |
_socketConnectionState[socket] = "CLOSED"; | |
_cleanupCounter++; | |
} | |
} | |
/*************************************************************************** | |
* _cleanupWatchdog, confirms all sockets have been disconnected before | |
* executing callback | |
* Returns: null | |
* Parameters: | |
* cb - function to run when all connections have been closed. | |
**************************************************************************/ | |
function _cleanupWatchdog(cb) { | |
if (_cleanupCounter < _totalSockets) { | |
imp.sleep(0.01); | |
_cleanupWatchdog(cb); | |
} else { | |
_cleanupCounter = 0; | |
cb(); | |
} | |
} | |
/*************************************************************************** | |
* _updateConnectionState - updates locally and connection instance | |
* Returns: this | |
* Parameters: | |
* conneciton - conneciton instance | |
* state - new state of connection | |
**************************************************************************/ | |
function _updateConnectionState(connection, state) { | |
_socketConnectionState[connection.socket] = state; | |
connection.setState(state); | |
return this; | |
} | |
// PRIVATE INTERRUPT FUNCTIONS | |
// --------------------------------------------- | |
/*************************************************************************** | |
* _interruptHandler, checks interrupt registers and calls appropriate | |
* handlers | |
* Returns: null | |
* Parameters: none | |
**************************************************************************/ | |
function _interruptHandler() { | |
local status = _wiz.getInterruptStatus(); | |
if (status.CONFLICT) _handleConflictInt(); | |
local status = _wiz.getSocketInterruptStatus(); | |
if (status.SOCKET_0) _handleSocketInt(0); | |
if (status.SOCKET_1) _handleSocketInt(1); | |
if (status.SOCKET_2) _handleSocketInt(2); | |
if (status.SOCKET_3) _handleSocketInt(3); | |
} | |
/*************************************************************************** | |
* _handleConflictInt, logs conflict error message & clears interrupt | |
* Returns: null | |
* Parameters: none | |
**************************************************************************/ | |
function _handleConflictInt() { | |
_wiz.clearInterrupt(W5500_CONFLICT_INT_TYPE); | |
server.error("Conflict Interrupt Occured. Please check IP Source and Destination addressess."); | |
} | |
/*************************************************************************** | |
* _handleSocketInt, handles/clears the specified socket interrupt | |
* Returns: null | |
* Parameters: socket the interrupt occurred on | |
**************************************************************************/ | |
function _handleSocketInt(socket) { | |
local status = _wiz.getSocketInterruptTypeStatus(socket); | |
local connection = _connections[socket]; | |
if (status.CONNECTED) { | |
server.log("Connection established on socket " + socket); | |
_wiz.clearSocketInterrupt(socket, W5500_CONNECTED_INT_TYPE); | |
_updateConnectionState(connection, "ESTABLISHED"); | |
local _connectionCallback = connection.getHandler("connect"); | |
if (_connectionCallback) { | |
connection.setConnectHandler(null); | |
imp.wakeup(0, function() { | |
_connectionCallback(null, connection); | |
}.bindenv(this)) | |
} | |
} | |
if (status.DISCONNECTED) { | |
server.log("Connection disconnected on socket " + socket); | |
_wiz.clearSocketInterrupt(socket, W5500_DISCONNECTED_INT_TYPE); | |
_wiz.sendSocketCommand(socket, W5500_SOCKET_CLOSE); | |
_updateConnectionState(connection, "CLOSED"); | |
_connections.rawdelete(connection.socket); | |
_avaiableConnections.push(socket); | |
// clear transmit and connection callbacks | |
connection.setTransmitHandler(null); | |
connection.setConnectHandler(null); | |
local _disconnectCallback = connection.getHandler("disconnect"); | |
// call disconnected callback | |
if (_disconnectCallback) { | |
imp.wakeup(0, function() { | |
_disconnectCallback(connection); | |
}.bindenv(this)); | |
} | |
} | |
if (status.SEND_COMPLETE) { | |
server.log("Send complete on socket " + socket); | |
_wiz.clearSocketInterrupt(socket, W5500_SEND_COMPLETE_INT_TYPE); | |
// call transmitting callback | |
local _transmitCallback = connection.getHandler("transmit"); | |
if (_transmitCallback) { | |
connection.setTransmitHandler(null); | |
imp.wakeup(0, function() { | |
_transmitCallback(null, connection); | |
}.bindenv(this)) | |
} | |
} | |
if (status.TIMEOUT) { | |
server.log("Timeout occurred on socket " + socket); | |
_wiz.clearSocketInterrupt(socket, W5500_TIMEOUT_INT_TYPE); | |
if (_socketConnectionState[socket] == "CONNECTING") { | |
_wiz.sendSocketCommand(socket, W5500_SOCKET_CLOSE); | |
_updateConnectionState(connection, "CLOSED"); | |
_connections.rawdelete(connection.socket); | |
_avaiableConnections.push(socket); | |
local _connectionCallback = connection.getHandler("connect"); | |
if (_connectionCallback) { | |
connection.setConnectHandler(null); | |
imp.wakeup(0, function() { | |
_connectionCallback("Error: Connection Timeout on socket " + socket, connection); | |
}.bindenv(this)) | |
} | |
} else { | |
local _transmitCallback = connection.getHandler("transmit"); | |
if (_transmitCallback) { | |
connection.setTransmitHandler(null); | |
imp.wakeup(0, function() { | |
_transmitCallback("Error: Transmission Timeout on socket " + socket, connection); | |
}.bindenv(this)) | |
} | |
} | |
} | |
if (status.DATA_RECEIVED) { | |
server.log("Data received on socket " + socket); | |
_wiz.clearSocketInterrupt(socket, W5500_DATA_RECEIVED_INT_TYPE); | |
receive(connection); // process incoming data | |
} | |
} | |
/*************************************************************************** | |
* _clearAllInterrupts, clears all interrupt registers | |
* Returns: this | |
* Parameters: none | |
**************************************************************************/ | |
function _clearAllInterrupts() { | |
_wiz.clearInterrupt(); | |
for(local socket = 0; socket < _totalSockets; socket++) { | |
_wiz.clearSocketInterrupt(socket); | |
} | |
return this; | |
} | |
// DEBUG/LOGGING FUNCTIONS | |
// --------------------------------------------- | |
/*************************************************************************** | |
* _logSocketInterruptStatus | |
* Returns: null | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function _logSocketInterruptStatus(socket) { | |
local status = _wiz.getSocketInterruptTypeStatus(socket); | |
foreach (k, v in status) { | |
server.log(k + ": " + v) | |
} | |
} | |
/*************************************************************************** | |
* _logConnectionState | |
* Returns: null | |
* Parameters: | |
* socket - select the socket using an integer 0-3 | |
**************************************************************************/ | |
function _logConnectionState(socket) { | |
local status = _wiz.getSocketStatus(socket); | |
switch(status) { | |
case W5500_SOCKET_STATUS_ESTABLISHED: | |
server.log("W5500_SOCKET_STATUS_ESTABLISHED"); | |
break; | |
case W5500_SOCKET_STATUS_SYNSENT: | |
server.log("W5500_SOCKET_STATUS_SYNSENT"); | |
break; | |
case W5500_SOCKET_STATUS_SYNRECV: | |
server.log("W5500_SOCKET_STATUS_SYNRECV"); | |
break; | |
case W5500_SOCKET_STATUS_CLOSED: | |
server.log("W5500_SOCKET_STATUS_CLOSED"); | |
break; | |
default : | |
server.log(status); | |
break; | |
} | |
} | |
/*************************************************************************** | |
* _debugLogging_Interruprts | |
* Returns: null | |
* Parameters: none | |
**************************************************************************/ | |
function _debugLogging_Interruprts() { | |
server.log(format("Interrupt reg: 0x%02X", _wiz.readReg(W5500_INTERRUPT, W5500_COMMON_REGISTER))); | |
server.log(format("Interrupt Mask: 0x%02X", _wiz.readReg(W5500_INTERRUPT_MASK, W5500_COMMON_REGISTER))); | |
server.log(format("Socket Interrupt reg: 0x%02X", _wiz.readReg(W5500_SOCKET_INTERRUPT, W5500_COMMON_REGISTER))); | |
server.log(format("Socket Interrupt Mask: 0x%02X", _wiz.readReg(W5500_SOCKET_INTERRUPT_MASK, W5500_COMMON_REGISTER))); | |
} | |
/*************************************************************************** | |
* _debugLogging_NetworkSettings | |
* Returns: null | |
* Parameters: none | |
**************************************************************************/ | |
function _debugLogging_NetworkSettings() { | |
_wiz._logGatewayIP(); | |
_wiz._logSourceAddr(); | |
_wiz._logSubnet(); | |
_wiz._logSourceIP(); | |
_wiz._logS0SourcePort(); | |
_wiz._logS0DestPort(); | |
_wiz._logS0DestIP(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment