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