1 /*
2  * Copyright (c) 2010 by Arduino LLC. All rights reserved.
3  *
4  * This file is free software; you can redistribute it and/or modify
5  * it under the terms of either the GNU General Public License version 2
6  * or the GNU Lesser General Public License version 2.1, both as
7  * published by the Free Software Foundation.
8  */
9 
10 #include <stdio.h>
11 #include <string.h>
12 
13 #include "w5100.h"
14 
15 // W5100 controller instance
16 W5100Class W5100;
17 
18 #define TX_RX_MAX_BUF_SIZE 2048
19 #define TX_BUF 0x1100
20 #define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE)
21 
22 #define TXBUF_BASE 0x4000
23 #define RXBUF_BASE 0x6000
24 
init(void)25 void W5100Class::init(void)
26 {
27   delay(300);
28 
29 #if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING)
30   SPI.begin();
31   initSS();
32 #else
33   SPI.begin(ETHERNET_SHIELD_SPI_CS);
34   // Set clock to 4Mhz (W5100 should support up to about 14Mhz)
35   SPI.setClockDivider(ETHERNET_SHIELD_SPI_CS, 21);
36   SPI.setDataMode(ETHERNET_SHIELD_SPI_CS, SPI_MODE0);
37 #endif
38   SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
39   writeMR(1<<RST);
40   writeTMSR(0x55);
41   writeRMSR(0x55);
42   SPI.endTransaction();
43 
44   for (int i=0; i<MAX_SOCK_NUM; i++) {
45     SBASE[i] = TXBUF_BASE + SSIZE * i;
46     RBASE[i] = RXBUF_BASE + RSIZE * i;
47   }
48 }
49 
getTXFreeSize(SOCKET s)50 uint16_t W5100Class::getTXFreeSize(SOCKET s)
51 {
52   uint16_t val=0, val1=0;
53   do {
54     val1 = readSnTX_FSR(s);
55     if (val1 != 0)
56       val = readSnTX_FSR(s);
57   }
58   while (val != val1);
59   return val;
60 }
61 
getRXReceivedSize(SOCKET s)62 uint16_t W5100Class::getRXReceivedSize(SOCKET s)
63 {
64   uint16_t val=0,val1=0;
65   do {
66     val1 = readSnRX_RSR(s);
67     if (val1 != 0)
68       val = readSnRX_RSR(s);
69   }
70   while (val != val1);
71   return val;
72 }
73 
74 
send_data_processing(SOCKET s,const uint8_t * data,uint16_t len)75 void W5100Class::send_data_processing(SOCKET s, const uint8_t *data, uint16_t len)
76 {
77   // This is same as having no offset in a call to send_data_processing_offset
78   send_data_processing_offset(s, 0, data, len);
79 }
80 
send_data_processing_offset(SOCKET s,uint16_t data_offset,const uint8_t * data,uint16_t len)81 void W5100Class::send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len)
82 {
83   uint16_t ptr = readSnTX_WR(s);
84   ptr += data_offset;
85   uint16_t offset = ptr & SMASK;
86   uint16_t dstAddr = offset + SBASE[s];
87 
88   if (offset + len > SSIZE)
89   {
90     // Wrap around circular buffer
91     uint16_t size = SSIZE - offset;
92     write(dstAddr, data, size);
93     write(SBASE[s], data + size, len - size);
94   }
95   else {
96     write(dstAddr, data, len);
97   }
98 
99   ptr += len;
100   writeSnTX_WR(s, ptr);
101 }
102 
103 
recv_data_processing(SOCKET s,uint8_t * data,uint16_t len,uint8_t peek)104 void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek)
105 {
106   uint16_t ptr;
107   ptr = readSnRX_RD(s);
108   read_data(s, ptr, data, len);
109   if (!peek)
110   {
111     ptr += len;
112     writeSnRX_RD(s, ptr);
113   }
114 }
115 
read_data(SOCKET s,volatile uint16_t src,volatile uint8_t * dst,uint16_t len)116 void W5100Class::read_data(SOCKET s, volatile uint16_t src, volatile uint8_t *dst, uint16_t len)
117 {
118   uint16_t size;
119   uint16_t src_mask;
120   uint16_t src_ptr;
121 
122   src_mask = src & RMASK;
123   src_ptr = RBASE[s] + src_mask;
124 
125   if( (src_mask + len) > RSIZE )
126   {
127     size = RSIZE - src_mask;
128     read(src_ptr, (uint8_t *)dst, size);
129     dst += size;
130     read(RBASE[s], (uint8_t *) dst, len - size);
131   }
132   else
133     read(src_ptr, (uint8_t *) dst, len);
134 }
135 
136 
write(uint16_t _addr,uint8_t _data)137 uint8_t W5100Class::write(uint16_t _addr, uint8_t _data)
138 {
139 #if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING)
140   setSS();
141   SPI.transfer(0xF0);
142   SPI.transfer(_addr >> 8);
143   SPI.transfer(_addr & 0xFF);
144   SPI.transfer(_data);
145   resetSS();
146 #else
147   SPI.transfer(ETHERNET_SHIELD_SPI_CS, 0xF0, SPI_CONTINUE);
148   SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr >> 8, SPI_CONTINUE);
149   SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr & 0xFF, SPI_CONTINUE);
150   SPI.transfer(ETHERNET_SHIELD_SPI_CS, _data);
151 #endif
152   return 1;
153 }
154 
write(uint16_t _addr,const uint8_t * _buf,uint16_t _len)155 uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len)
156 {
157   for (uint16_t i=0; i<_len; i++)
158   {
159 #if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING)
160     setSS();
161     SPI.transfer(0xF0);
162     SPI.transfer(_addr >> 8);
163     SPI.transfer(_addr & 0xFF);
164     _addr++;
165     SPI.transfer(_buf[i]);
166     resetSS();
167 #else
168     SPI.transfer(ETHERNET_SHIELD_SPI_CS, 0xF0, SPI_CONTINUE);
169     SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr >> 8, SPI_CONTINUE);
170     SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr & 0xFF, SPI_CONTINUE);
171     SPI.transfer(ETHERNET_SHIELD_SPI_CS, _buf[i]);
172     _addr++;
173 #endif
174   }
175   return _len;
176 }
177 
read(uint16_t _addr)178 uint8_t W5100Class::read(uint16_t _addr)
179 {
180 #if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING)
181   setSS();
182   SPI.transfer(0x0F);
183   SPI.transfer(_addr >> 8);
184   SPI.transfer(_addr & 0xFF);
185   uint8_t _data = SPI.transfer(0);
186   resetSS();
187 #else
188   SPI.transfer(ETHERNET_SHIELD_SPI_CS, 0x0F, SPI_CONTINUE);
189   SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr >> 8, SPI_CONTINUE);
190   SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr & 0xFF, SPI_CONTINUE);
191   uint8_t _data = SPI.transfer(ETHERNET_SHIELD_SPI_CS, 0);
192 #endif
193   return _data;
194 }
195 
read(uint16_t _addr,uint8_t * _buf,uint16_t _len)196 uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len)
197 {
198   for (uint16_t i=0; i<_len; i++)
199   {
200 #if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING)
201     setSS();
202     SPI.transfer(0x0F);
203     SPI.transfer(_addr >> 8);
204     SPI.transfer(_addr & 0xFF);
205     _addr++;
206     _buf[i] = SPI.transfer(0);
207     resetSS();
208 #else
209     SPI.transfer(ETHERNET_SHIELD_SPI_CS, 0x0F, SPI_CONTINUE);
210     SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr >> 8, SPI_CONTINUE);
211     SPI.transfer(ETHERNET_SHIELD_SPI_CS, _addr & 0xFF, SPI_CONTINUE);
212     _buf[i] = SPI.transfer(ETHERNET_SHIELD_SPI_CS, 0);
213     _addr++;
214 #endif
215   }
216   return _len;
217 }
218 
execCmdSn(SOCKET s,SockCMD _cmd)219 void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) {
220   // Send command to socket
221   writeSnCR(s, _cmd);
222   // Wait for command to complete
223   while (readSnCR(s))
224     ;
225 }
226