/* * Copyright (c) 2010 by Arduino LLC. All rights reserved. * * 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 #include #include "w5100.h" // W5100 controller instance W5100Class W5100; #define TX_RX_MAX_BUF_SIZE 2048 #define TX_BUF 0x1100 #define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE) #define TXBUF_BASE 0x4000 #define RXBUF_BASE 0x6000 void W5100Class::init(void) { delay(300); #if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING) SPI.begin(); initSS(); #else SPI.begin(ETHERNET_SHIELD_SPI_CS); // Set clock to 4Mhz (W5100 should support up to about 14Mhz) SPI.setClockDivider(ETHERNET_SHIELD_SPI_CS, 21); SPI.setDataMode(ETHERNET_SHIELD_SPI_CS, SPI_MODE0); #endif SPI.beginTransaction(SPI_ETHERNET_SETTINGS); writeMR(1< SSIZE) { // Wrap around circular buffer uint16_t size = SSIZE - offset; write(dstAddr, data, size); write(SBASE[s], data + size, len - size); } else { write(dstAddr, data, len); } ptr += len; writeSnTX_WR(s, ptr); } void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek) { uint16_t ptr; ptr = readSnRX_RD(s); read_data(s, ptr, data, len); if (!peek) { ptr += len; writeSnRX_RD(s, ptr); } } void W5100Class::read_data(SOCKET s, volatile uint16_t src, volatile uint8_t *dst, uint16_t len) { uint16_t size; uint16_t src_mask; uint16_t src_ptr; src_mask = src & RMASK; src_ptr = RBASE[s] + src_mask; if( (src_mask + len) > RSIZE ) { size = RSIZE - src_mask; read(src_ptr, (uint8_t *)dst, size); dst += size; read(RBASE[s], (uint8_t *) dst, len - size); } else read(src_ptr, (uint8_t *) dst, len); } uint8_t W5100Class::write(uint16_t _addr, uint8_t _data) { #if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING) setSS(); SPI.transfer(0xF0); SPI.transfer(_addr >> 8); SPI.transfer(_addr & 0xFF); SPI.transfer(_data); resetSS(); #else SPI.transfer(ETHERNET_SHIELD_SPI_CS, 0xF0, SPI_CONTINUE); SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr >> 8, SPI_CONTINUE); SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr & 0xFF, SPI_CONTINUE); SPI.transfer(ETHERNET_SHIELD_SPI_CS, _data); #endif return 1; } uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len) { for (uint16_t i=0; i<_len; i++) { #if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING) setSS(); SPI.transfer(0xF0); SPI.transfer(_addr >> 8); SPI.transfer(_addr & 0xFF); _addr++; SPI.transfer(_buf[i]); resetSS(); #else SPI.transfer(ETHERNET_SHIELD_SPI_CS, 0xF0, SPI_CONTINUE); SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr >> 8, SPI_CONTINUE); SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr & 0xFF, SPI_CONTINUE); SPI.transfer(ETHERNET_SHIELD_SPI_CS, _buf[i]); _addr++; #endif } return _len; } uint8_t W5100Class::read(uint16_t _addr) { #if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING) setSS(); SPI.transfer(0x0F); SPI.transfer(_addr >> 8); SPI.transfer(_addr & 0xFF); uint8_t _data = SPI.transfer(0); resetSS(); #else SPI.transfer(ETHERNET_SHIELD_SPI_CS, 0x0F, SPI_CONTINUE); SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr >> 8, SPI_CONTINUE); SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr & 0xFF, SPI_CONTINUE); uint8_t _data = SPI.transfer(ETHERNET_SHIELD_SPI_CS, 0); #endif return _data; } uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len) { for (uint16_t i=0; i<_len; i++) { #if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING) setSS(); SPI.transfer(0x0F); SPI.transfer(_addr >> 8); SPI.transfer(_addr & 0xFF); _addr++; _buf[i] = SPI.transfer(0); resetSS(); #else SPI.transfer(ETHERNET_SHIELD_SPI_CS, 0x0F, SPI_CONTINUE); SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr >> 8, SPI_CONTINUE); SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr & 0xFF, SPI_CONTINUE); _buf[i] = SPI.transfer(ETHERNET_SHIELD_SPI_CS, 0); _addr++; #endif } return _len; } void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) { // Send command to socket writeSnCR(s, _cmd); // Wait for command to complete while (readSnCR(s)) ; }