Aktuální adresář: FITkit /
trunk /
mcu /
libs /
enc28j60 /
enc28j60_spi_tx.c
1 /*******************************************************************************
2
3 Copyright (C) 2010 Brno University of Technology,
4 Faculty of Information Technology
5 Author(s): Martin Musil <xmusil34 AT fit.vutbr.cz>
6
7 LICENSE TERMS
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in
16 the documentation and/or other materials provided with the
17 distribution.
18 3. All advertising materials mentioning features or use of this software
19 or firmware must display the following acknowledgement:
20
21 This product includes software developed by the University of
22 Technology, Faculty of Information Technology, Brno and its
23 contributors.
24
25 4. Neither the name of the Company nor the names of its contributors
26 may be used to endorse or promote products derived from this
27 software without specific prior written permission.
28
29 This software or firmware is provided ``as is'', and any express or implied
30 warranties, including, but not limited to, the implied warranties of
31 merchantability and fitness for a particular purpose are disclaimed.
32 In no event shall the company or contributors be liable for any
33 direct, indirect, incidental, special, exemplary, or consequential
34 damages (including, but not limited to, procurement of substitute
35 goods or services; loss of use, data, or profits; or business
36 interruption) however caused and on any theory of liability, whether
37 in contract, strict liability, or tort (including negligence or
38 otherwise) arising in any way out of the use of this software, even
39 if advised of the possibility of such damage.
40
41 $Id$
42
43 *******************************************************************************/
44
45 #include "enc28j60_spi_tx.h"
46 #include "enc28j60_spi.h"
47 #include "fspi.h"
48
49 //hlavni ukazatele pro praci s buffery
50 unsigned int tx_ptr;
51 unsigned int tx_end_ptr;
52 unsigned int TXST;
53 unsigned int TXND;
54
55 //promenna, znaci aktualni buffer
56 unsigned char act_tx;
57
58 //zamek bufferu
59 #define LOCKED 1
60 #define UNLOCKED 0
61 char tx1_lock = UNLOCKED;
62 char tx2_lock = UNLOCKED;
63 char tx3_lock = UNLOCKED;
64
65 //promenne pro ulozeni protokolu, ktery se pres ne odesila
66 char tx1_protocol;
67 char tx2_protocol;
68 char tx3_protocol;
69
70 //ukazatele pro jednotlive buffery, slouzi pro uchovavani hodnot behem prepinani
71 unsigned int tx1_ptr;
72 unsigned int tx2_ptr;
73 unsigned int tx3_ptr;
74
75 unsigned int tx1_end_ptr;
76 unsigned int tx2_end_ptr;
77 unsigned int tx3_end_ptr;
78
79 //vnitrni pomocne funkce
80 char tx_protocol(unsigned char protocol);
81
82
83 //************************************************
84 //odesilaci buffer
85 //************************************************
86
87 /**
88
89 **/
90 char tx_init(unsigned char protocol){
91
92 int timer = TIMEOUT; //timeout
93
94 //kontrola dokonceni odesilani predchoziho paketu
95 while((read_reg8(ECON1,NO_DUMMY) & ECON1_TXRTS) && (timer-- > 0) );
96
97 if(timer == 0) //timeout vyprsel
98 return -1;
99
100 //buffer pro UDP pakety
101 if(protocol == UDP_PROTO){
102
103 if(tx1_lock == LOCKED){ //tx1 ma zamek,aby nedoslo k nahodnemu prepsani jeste
104 return -1; //neodeslaneho obsahu bufferu jinym. napr. pri odesilani
105 } //paketu z obsluhy preruseni
106
107 tx1_lock = LOCKED;
108 tx_save(act_tx);
109
110 TXST = TX1ST; //restart ukazatelu na zacatek a konec vyhrazene pameti
111 TXND = TX1ND;
112 act_tx = TX1; //bufferem je TX1
113
114 select_bank(0);
115
116 write_reg16(ETXST,TXST); // zapsani ukazatele na zacatek bufferu do ENC28
117 write_reg16(ETXND,TXST);
118
119 tx_ptr = TX1ST; //inicializace ukazatele do bufferu
120 tx1_ptr = TX1ST; //nastaveni pomocnych ukazatelu (jsou pro
121 tx1_end_ptr = TX1ST; // uchovani hodnot behem prepinani funkcemi tx_save a tx_load)
122 tx1_protocol = protocol;
123
124 return tx_protocol(protocol);
125 }
126
127 //buffer pro TCP pakety
128 else if(protocol == TCP_PROTO){
129
130 if(tx3_lock == LOCKED){ //tx3 ma zamek, zde u TCP slouzi k tomu, aby nebylo mozne
131 return -1; //odesilat dalsi paket, dokud predchozi nebyl odeslan
132 } // zamek odemyka stavovy automat TCP spojeni
133 tx3_lock = LOCKED;
134
135 tx_save(act_tx);
136
137 TXST = TX3ST; //restart ukazatelu na zacatek a konec vyhrazene pameti
138 TXND = TX3ND;
139 act_tx = TX3; //bufferem je TX3
140
141 select_bank(0);
142
143 write_reg16(ETXST,TXST); // zapsani ukazatele na zacatek bufferu do ENC28
144 write_reg16(ETXND,TXST);
145
146 tx_ptr = TX3ST; //inicializace ukazatele do bufferu
147 tx3_ptr = TX3ST; //nastaveni pomocnych ukazatelu (jsou pro
148 tx3_end_ptr = TX3ST; // uchovani hodnot behem prepinani funkcemi tx_save a tx_load)
149 tx3_protocol = protocol;
150
151 return tx_protocol(protocol);
152 }
153
154 //buffer pro automaticke odpovedi a ARP dotazy
155 else if((protocol == ICMP_PROTO) | (protocol == TCP_PROTO_HEADER_ONLY)){
156
157 if(tx2_lock == LOCKED){ //tx2 ma zamek,aby nedoslo k nahodnemu prepsani jeste
158 return -1; //neodeslaneho obsahu bufferu jinym. napr. pri odesilani
159 } //paketu z obsluhy preruseni
160
161 tx2_lock = LOCKED;
162 tx_save(act_tx);
163
164 TXST = TX2ST; //restart ukazatelu na zacatek a konec vyhrazene pameti
165 TXND = TX2ND;
166 act_tx = TX2; //bufferem je TX2
167
168 select_bank(0);
169
170 write_reg16(ETXST,TXST); // zapsani ukazatele na zacatek bufferu do ENC28
171 write_reg16(ETXND,TXST); // --||-- konec
172
173 tx_ptr = TX2ST; //inicializace ukazatele do bufferu
174 tx2_ptr = TX2ST; //nastaveni pomocnych ukazatelu (jsou pro
175 tx2_end_ptr = TX2ST; // uchovani hodnot behem prepinani funkcemi tx_save a tx_load)
176 tx2_protocol = protocol;
177
178 return tx_protocol(protocol);
179 }
180 else if((protocol == ARP_PROTO)){
181
182 tx_save(act_tx);
183
184 TXST = TX4ST; //restart ukazatelu na zacatek a konec vyhrazene pameti
185 TXND = TX4ND;
186 act_tx = TX4; //bufferem je TX4
187
188 select_bank(0);
189
190 write_reg16(ETXST,TXST); // zapsani ukazatele na zacatek bufferu do ENC28
191 write_reg16(ETXND,TXST); // --||-- konec
192
193 tx_ptr = TX4ST; //inicializace ukazatele do bufferu
194
195 return tx_protocol(protocol);
196 }
197
198
199 return -1;
200 }
201
202 /*Fce pro preskoceni mista pro hlavicky podle pouziteho protokolu*/
203 char tx_protocol(unsigned char protocol){
204
205 switch(protocol){
206 case TCP_PROTO_HEADER_ONLY:
207 case TCP_PROTO:
208 tx_ptr = TXST + CTRL_LEN + ETH_HEADER_LEN + IP_HEADER_LEN + TCP_HEADER_LEN;
209 break;
210 case UDP_PROTO:
211 tx_ptr = TXST + CTRL_LEN + ETH_HEADER_LEN + IP_HEADER_LEN + UDP_HEADER_LEN;
212 break;
213 case ICMP_PROTO:
214 tx_ptr = TXST + CTRL_LEN + ETH_HEADER_LEN + IP_HEADER_LEN + ICMP_HEADER_LEN;
215 break;
216 case ARP_PROTO:
217 tx_ptr = TXST + CTRL_LEN + ETH_HEADER_LEN;
218 break;
219 default:
220 return -1;
221 }
222
223 select_bank(0);
224 write_reg16(EWRPT,tx_ptr); //posun na zacatek datove casti
225
226 return 0;
227 }
228
229 /**
230
231
232 **/
233 void tx_rewind(){
234
235 switch(act_tx){
236 case TX1:
237 tx_protocol(tx1_protocol);
238 break;
239 case TX2:
240 tx_protocol(tx2_protocol);
241 break;
242 case TX3:
243 tx_protocol(tx3_protocol);
244 break;
245 }
246 }
247
248
249
250 /**
251
252 **/
253 void tx_seek(unsigned char header){
254 switch(header){
255 case CTRL:
256 tx_ptr = TXST;
257 break;
258 case ETH_HEADER:
259 tx_ptr = TXST + CTRL_LEN;
260 break;
261 case IP_HEADER:
262 tx_ptr = TXST + CTRL_LEN + ETH_HEADER_LEN;
263 break;
264 case ICMP_HEADER:
265 case TCP_HEADER:
266 case UDP_HEADER:
267 tx_ptr = TXST + CTRL_LEN + ETH_HEADER_LEN + IP_HEADER_LEN;
268 break;
269 }
270
271 select_bank(0);
272 write_reg16(EWRPT,tx_ptr);
273 return;
274 }
275
276 /**
277
278
279
280 **/
281 inline void tx_close(){
282 select_bank(0);
283 tx_end_ptr = tx_ptr;
284 write_reg16(ETXND,tx_end_ptr-1); //tx_end_ptr ukazatel ukazuje na misto, kde jeste neni nic zapsano, proto -1
285 } //ETXND musi ukazovat na posledni bajt dat
286
287
288 /**
289
290 **/
291 void tx_save(unsigned char buffer){
292
293 //ulozeni stavu predchoziho bufferu
294 switch(buffer){
295 case TX1:
296 tx1_ptr = tx_ptr; //ulozeni stavu TX1
297 tx1_end_ptr = tx_end_ptr;
298 break;
299
300 case TX2:
301 tx2_ptr = tx_ptr; //ulozeni stavu TX2
302 tx2_end_ptr = tx_end_ptr;
303 break;
304
305 case TX3:
306 tx3_ptr = tx_ptr; //ulozeni stavu TX3
307 tx3_end_ptr = tx_end_ptr;
308 break;
309 }
310 return;
311 }
312
313
314 /**
315
316 **/
317 void tx_load(unsigned char buffer){
318
319 switch(buffer){
320 case TX1:
321 TXST = TX1ST; //obnoveni stavu pro TX1
322 TXND = TX1ND;
323 tx_ptr = tx1_ptr;
324 tx_end_ptr = tx1_end_ptr;
325 act_tx = TX1;
326 break;
327
328 case TX2:
329 TXST = TX2ST; //obnoveni stavu pro TX2
330 TXND = TX2ND;
331 tx_ptr = tx2_ptr;
332 tx_end_ptr = tx2_end_ptr;
333 act_tx = TX2;
334 break;
335
336 case TX3:
337 TXST = TX3ST; //obnoveni stavu pro TX3
338 TXND = TX3ND;
339 tx_ptr = tx3_ptr;
340 tx_end_ptr = tx3_end_ptr;
341 act_tx = TX3;
342 break;
343 }
344
345 write_reg16(EWRPT,tx_ptr); // nastaveni ukazatele pro zapis
346 write_reg16(ETXST,TXST); // zapsani ukazatele na zacatek bufferu do ENC28
347 write_reg16(ETXND,tx_end_ptr-1); //tx_end_ptr ukazatel ukazuje na misto, kde jeste neni nic zapsano, proto -1
348 //ETXND musi ukazovat na posledni bajt dat
349
350 return;
351 }
352
353 /**
354
355 **/
356 unsigned char tx_act(){
357
358 return act_tx;
359 }
360
361 /**
362
363 **/
364 unsigned char tx_putc(char c){
365
366 if(tx_ptr > TXND)
367 return 0;
368 else{
369 spi_putc(c);
370 tx_ptr++;
371 return 1;
372 }
373 }
374
375 /**
376
377 **/
378 unsigned int tx_write(void* ptr, unsigned int length){
379
380 int remaining = tx_left();
381
382 if(tx_ptr > TXND)
383 return 0;
384 else if(length >= remaining){
385 spi_write(ptr, remaining);
386 tx_ptr += remaining;
387 return remaining;
388 }
389 else{
390 spi_write(ptr, length);
391 tx_ptr += length;
392 return length;
393 }
394 return 0;
395 }
396
397 /**
398
399 **/
400 unsigned int tx_fill(unsigned char value, unsigned int length){
401
402 int remaining = tx_left();
403
404 if(tx_ptr > TXND)
405 return 0;
406 else if(length >= remaining){
407 spi_fill(value, remaining);
408 tx_ptr += remaining;
409 return remaining;
410 }
411 else{
412 spi_fill(value, length);
413 tx_ptr += length;
414 return length;
415 }
416 return 0;
417 }
418
419 /**
420
421
422 **/
423 unsigned int tx_skip(unsigned int length){
424
425 int remaining = tx_left();
426
427 if(tx_ptr > TXND)
428 return 0;
429 else if(length >= remaining){
430 tx_ptr += remaining;
431 write_reg16(EWRPT,tx_ptr);
432 return remaining;
433 }
434 else{
435 tx_ptr += length;
436 write_reg16(EWRPT,tx_ptr);
437 return length;
438 }
439 return 0;
440 }
441
442 /**
443
444 **/
445 char tx_send(){
446
447 int timer = TIMEOUT; //timeout
448
449 while(( (read_reg8(ECON1,NO_DUMMY) & ECON1_TXRTS) > 0) & (timer-- > 0) ); //kontrola odeslani predchoziho paketu
450
451
452 if(timer == 0){ //timeout vyprsel
453 if(act_tx == TX1){ //odemknuti TX1 po nevydarenem odeslani
454 tx_unlock(TX1);
455 }
456 else if(act_tx == TX2){
457 tx_unlock(TX2);
458 }
459 return -1;
460 }
461
462 // prepsani registru s nastavenim paddingu,crc... sam od sebe se nejak "maze"
463 //mozna hw zavada vybranyho kousku
464 select_bank(2);
465 write_reg8(MACON3,MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FULDPX);
466
467 bf_set(ECON1,ECON1_TXRTS);
468
469 if(act_tx == TX1){ //odemknuti TX1
470 tx_unlock(TX1);
471 }
472 else if(act_tx == TX2){
473 tx_unlock(TX2);
474 }
475 return 0;
476 }
477
478
479 /**
480
481 **/
482 inline unsigned int tx_left(){
483
484 return TXND - tx_ptr +1; //kompenzace, TXND je posledni bajt zpravy, tx_ptr tam musi umoznit zapisovat
485 }
486
487 /**
488
489 **/
490 inline unsigned int tx_data_len(){
491
492 return tx_end_ptr - tx_ptr;
493 }
494
495 /**
496
497 **/
498 unsigned int tx_checksum(){
499
500 //vyuziti vnitrniho DMA radice v ENC28J60 pro spocitani checksumu
501 select_bank(0);
502 write_reg16(EDMAST,tx_ptr);
503 write_reg16(EDMAND,tx_end_ptr -1);
504 bf_clear(EIR,EIR_DMAIF);
505
506 bf_set(ECON1,ECON1_CSUMEN | ECON1_DMAST);
507
508 while((read_reg8(EIR,NO_DUMMY) & EIR_DMAIF ) == 0);
509
510 return read_reg16(EDMACS,NO_DUMMY);
511
512 }
513
514
515 /**
516
517 **/
518 inline void tx_unlock(unsigned char buffer){
519
520 if(buffer == TX1)
521 tx1_lock = UNLOCKED;
522 else if(buffer == TX2)
523 tx2_lock = UNLOCKED;
524 else if(buffer == TX3)
525 tx3_lock = UNLOCKED;
526
527 return;
528 }
529