]> git.llucax.com Git - z.facultad/66.09/etherled.git/blob - pruebas/keil/red_test_anda/etherdev.c
Implementa el protocolo ELP sobre UDP. Tiene problemas cuando los leds estan
[z.facultad/66.09/etherled.git] / pruebas / keil / red_test_anda / etherdev.c
1 // vim: set et sw=4 sts=4 :     
2
3 #include "types.h"
4 #include "etherdev.h"
5
6 void sleep(unsigned char);
7
8 #ifdef SDCC
9 static xdata at 0x0080 byte leds1;
10 static xdata at 0x00c0 byte leds2;
11 #else
12 static byte xdata leds1 _at_ 0x0080;
13 static byte xdata leds2 _at_ 0x00c0;
14 #endif
15
16 unsigned char uip_buf[80] =
17 {
18         0x00, 0x0c, 0x6e, 0x37, 0x19, 0xbf, // MAC destino
19         //0x00, 0x80, 0xc7, 0x42, 0x8d, 0x27, // MAC destino
20         0x00, 0x0c, 0x6e, 0x37, 0x19, 0xbe, // MAC fuente
21         0x00, 0x00, // Type
22 };
23
24 unsigned int uip_len = 14;
25
26 // Packet transmit & receive buffer configuration
27 #define ETH_TX_PAGE_START  0x40    // 0x4000 Tx buffer is  6 * 256 = 1536 bytes
28 #define ETH_RX_PAGE_START  0x46    // 0x4600 Rx buffer is 26 * 256 = 6656 bytes
29 #define ETH_RX_PAGE_STOP   0x60    // 0x6000
30
31 #define ETH_ADDR_PORT_MASK 0x1F                 // 00011111y
32 #define ETH_DATA_PORT_MASK 0xFF                 // 11111111y
33
34 #define ETH_MIN_PACKET_LEN 0x3C                 // 60 bytes
35
36
37 static void etherdev_reg_write(unsigned char reg, unsigned char wr_data);
38 static unsigned char etherdev_reg_read(unsigned char reg);
39
40 // Manipulate PS1 & PS0 in CR to select RTL8019AS register page. 
41 #define ETHERDEV_SELECT_REG_PAGE(page)                                      \
42           do                                                                \
43           {                                                                 \
44               etherdev_reg_write(CR, etherdev_reg_read(CR) & ~(PS1 | PS0)); \
45               etherdev_reg_write(CR, etherdev_reg_read(CR) | (page << 6));  \
46           } while(0)
47
48
49 static void etherdev_reg_write(unsigned char reg, unsigned char wr_data)
50 {
51     // Select register address.
52     ETH_ADDR_PORT &= ~ETH_ADDR_PORT_MASK; 
53     ETH_ADDR_PORT |= reg;
54
55     // Output register data to port.
56     ETH_DATA_PORT = wr_data;
57
58     // Clock register data into RTL8019AS.
59     // IOR & IOW are both active low.
60     NICE = 0;
61     IOW = 0;
62     IOW = 1;
63     NICE = 1;
64
65     return;
66
67
68
69 static unsigned char etherdev_reg_read(unsigned char reg)
70 {
71     unsigned char rd_data;
72
73     // Select register address.
74     ETH_ADDR_PORT &= ~ETH_ADDR_PORT_MASK;
75     ETH_ADDR_PORT |= reg;
76
77     // Set register data port as input.
78     ETH_DATA_PORT = ETH_DATA_PORT_MASK;
79
80     // Enable register data output from RTL8019AS.
81     NICE = 0;
82     IOR = 0;
83
84     // Read register data from port.
85     rd_data = ETH_DATA_PORT;
86
87     // Disable register data output from RTL8019AS.
88     IOR = 1; 
89     NICE = 1;   
90
91     return rd_data;
92
93
94
95 /*
96                                                                      
97                             etherdev_init()                          
98                                                                      
99   Returns: 1 on success, 0 on failure.                               
100   Refer to National Semiconductor DP8390 App Note 874, July 1993.    
101                                                                      
102  */
103 bool etherdev_init(void)
104 {
105     // Set IOR & IOW as they're active low.
106     IOR = 1;
107     IOW = 1;
108     NICE = 1;
109
110     // Set register data port as input.
111     ETH_DATA_PORT = ETH_DATA_PORT_MASK;
112
113     // Configure RTL8019AS ethernet controller.
114
115     // Keil startup code takes 4ms to execute (18.432MHz, X1 mode).
116     // That leaves plenty of time for the RTL8019AS to read it's
117     // configuration in from the 9346 EEPROM before we get here.
118
119     // Select RTL8019AS register page 0.
120     ETHERDEV_SELECT_REG_PAGE(0);
121
122     // Check if RTL8019AS fully reset.
123     if(!(etherdev_reg_read(ISR) & RST))
124     {
125         return 0;
126     }
127
128     // Stop RTL8019AS, select page 0 and abort DMA operation.
129     etherdev_reg_write(CR, ABORT | STP);
130
131     // Initialise data configuration register. 
132     // FIFO threshold 8 bytes, no loopback, don't use auto send packet.
133     etherdev_reg_write(DCR, FT1 | LS);
134
135     // Reset remote byte count registers.
136     etherdev_reg_write(RBCR0, 0x00);
137     etherdev_reg_write(RBCR1, 0x00);
138
139     // Receive configuration register to monitor mode.
140     etherdev_reg_write(RCR, MON);
141
142     // Initialise transmit configuration register to loopback internally.
143     etherdev_reg_write(TCR, MODE1);
144
145     // Clear interrupt status register bits by writing 1 to each.
146     etherdev_reg_write(ISR, 0xFF);
147
148     // Mask all interrupts in mask register.
149     etherdev_reg_write(IMR, 0x00);
150     
151     // Obtengo MAC de la placa
152     etherdev_reg_write(RBCR0, 0x0c); // Vamos a leer 12 bytes (2 x 6)
153     etherdev_reg_write(RBCR1, 0x00); 
154     etherdev_reg_write(RSAR0, 0x00); // En la dirección 0x0000
155     etherdev_reg_write(RSAR1, 0x00);
156     etherdev_reg_write(CR, READ | STA); // Comienza lectura
157     uip_buf[6] = etherdev_reg_read(RDMA);
158     etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
159     uip_buf[7] = etherdev_reg_read(RDMA);
160     etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
161     uip_buf[8] = etherdev_reg_read(RDMA);
162     etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
163     uip_buf[9] = etherdev_reg_read(RDMA);
164     etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
165     uip_buf[10] = etherdev_reg_read(RDMA);
166     etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
167     uip_buf[11] = etherdev_reg_read(RDMA);
168     etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
169
170     // Wait until remote DMA operation completes.
171     while(!(etherdev_reg_read(ISR) & RDC)) continue;
172
173     // Abort/ complete DMA operation.
174     etherdev_reg_write(CR, ABORT | STP);
175
176     // Limpia ISR
177     etherdev_reg_write(ISR, RDC);
178
179     // Set transmit page start.
180     etherdev_reg_write(TPSR, ETH_TX_PAGE_START);
181
182     // Set receive buffer page start.
183     etherdev_reg_write(PSTART, ETH_RX_PAGE_START);
184
185     // Initialise last receive buffer read pointer.
186     etherdev_reg_write(BNRY, ETH_RX_PAGE_START);
187
188     // Set receive buffer page stop.
189     etherdev_reg_write(PSTOP, ETH_RX_PAGE_STOP);
190
191     // Select RTL8019AS register page 1.
192     etherdev_reg_write(CR, ABORT | PAGE1 | STP);
193
194     // Initialise current packet receive buffer page pointer
195     etherdev_reg_write(CURR, ETH_RX_PAGE_START + 1);
196
197     // Set physical address
198     etherdev_reg_write(PAR0, uip_buf[6]);
199     etherdev_reg_write(PAR1, uip_buf[7]);
200     etherdev_reg_write(PAR2, uip_buf[8]);
201     etherdev_reg_write(PAR3, uip_buf[9]);
202     etherdev_reg_write(PAR4, uip_buf[10]);
203     etherdev_reg_write(PAR5, uip_buf[11]);
204
205     // Select RTL8019AS register page 0 and abort DMA operation.
206     etherdev_reg_write(CR, ABORT | STP);
207
208     // Restart RTL8019AS. 
209     etherdev_reg_write(CR, ABORT | STA);
210
211     // Initialise transmit configuration register for normal operation.
212     etherdev_reg_write(TCR, MODE0);
213
214     // Receive configuration register to accept broadcast packets.
215     etherdev_reg_write(RCR, AB);
216
217     return 1;
218 }
219
220
221 /*
222                                                                      
223                            etherdev_send()                           
224                                                                      
225  Send the packet in the uip_buf and uip_appdata buffers using the    
226  RTL8019AS ethernet card.                                            
227                                                                      
228  */
229 void etherdev_send(void)
230 {
231     unsigned int i;
232
233     // Setup for DMA transfer from uip_buf & uip_appdata buffers to RTL8019AS.
234
235     // Select RTL8019AS register page 0 and abort DMA operation.
236     etherdev_reg_write(CR, ABORT | STA);
237
238     // Wait until pending transmit operation completes.
239     while(etherdev_reg_read(CR) & TXP) continue;
240
241     // Set remote DMA start address registers to indicate where to load packet.
242     etherdev_reg_write(RSAR0, 0x00);
243     etherdev_reg_write(RSAR1, ETH_TX_PAGE_START);
244
245     // Set remote DMA byte count registers to indicate length of packet load.
246     etherdev_reg_write(RBCR0, (unsigned char)(uip_len & 0xFF));
247     etherdev_reg_write(RBCR1, (unsigned char)(uip_len >> 8));
248
249     // Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS.
250     etherdev_reg_write(CR, WRITE | STA);
251
252     // DMA transfer packet from uip_buf & uip_appdata to RTL8019AS local
253     // transmit buffer memory.
254     for(i = 0; i < uip_len; i++)
255     {
256         etherdev_reg_write(RDMA, uip_buf[i]);
257     }
258
259     // Wait until remote DMA operation complete.
260     while(!(etherdev_reg_read(ISR) & RDC)) continue;
261
262     // Clear remote DMA complete interrupt status register bit.
263     etherdev_reg_write(ISR, RDC);
264
265     // Abort/ complete DMA operation.
266     etherdev_reg_write(CR, ABORT | STA);
267
268     // Set transmit page start to indicate packet start.
269     etherdev_reg_write(TPSR, ETH_TX_PAGE_START);
270
271     // Ethernet packets must be > 60 bytes, otherwise are rejected as runts.
272     if(uip_len < ETH_MIN_PACKET_LEN)
273     {
274         uip_len = ETH_MIN_PACKET_LEN;
275     }
276
277     // Set transmit byte count registers to indicate packet length.
278     etherdev_reg_write(TBCR0, (unsigned char)(uip_len & 0xFF));
279     etherdev_reg_write(TBCR1, (unsigned char)(uip_len >> 8));
280
281     // Issue command for RTL8019AS to transmit packet from it's local buffer.
282     etherdev_reg_write(CR, ABORT | TXP | STA);
283
284     return;
285 }
286
287
288 static void etherdev_reset()
289 {
290     bit retransmit = etherdev_reg_read(CR) & TXP;
291
292     // If the receive buffer ring has overflowed we dump the whole
293     // thing and start over. There is no way of knowing whether the
294     // data it contains is uncorrupted, or will cause us grief.
295
296     // Stop RTL8019AS and abort DMA operation.
297     etherdev_reg_write(CR, ABORT | STP);
298
299     // Wait for controller to halt after any current tx completes.
300     while(!(etherdev_reg_read(ISR) & RST)) continue;
301
302     // Reset remote byte count registers.
303     etherdev_reg_write(RBCR0, 0x00);
304     etherdev_reg_write(RBCR1, 0x00);
305
306     // Check whether currently transmitting a packet.
307     if(retransmit)
308     {
309         // If neither a successful transmission nor a tx abort error 
310         // has occured, then flag current tx packet for resend.
311         if(etherdev_reg_read(ISR) & (PTX | TXE))
312         {
313             retransmit = 0;
314         }
315     }
316
317     // Set transmit configuration register to loopback internally.
318     etherdev_reg_write(TCR, MODE1);
319
320     // Restart the RTL8019AS.
321     etherdev_reg_write(CR, ABORT | STA);
322
323     // Re-initialise last receive buffer read pointer.
324     etherdev_reg_write(BNRY, ETH_RX_PAGE_START);
325
326     // Select RTL8019AS register page 1.
327     ETHERDEV_SELECT_REG_PAGE(1);
328
329     // Re-initialise current packet receive buffer page pointer.
330     etherdev_reg_write(CURR, ETH_RX_PAGE_START + 1);
331
332     // Select RTL8019AS register page 0.
333     ETHERDEV_SELECT_REG_PAGE(0);
334
335     // Clear rx buffer overflow & packet received interrupt flags.
336     etherdev_reg_write(ISR, PRX | OVW);
337
338     // Re-itialise transmit configuration reg for normal operation.
339     etherdev_reg_write(TCR, MODE0);
340
341     if(retransmit)
342     {
343         // Retransmit packet in RTL8019AS local tx buffer.
344         etherdev_reg_write(CR, ABORT | TXP | STA);
345     }
346 }
347
348
349 unsigned int etherdev_read(void)
350 {    
351     unsigned int len = 0;
352
353     // Check if the rx buffer has overflowed.
354     if (etherdev_reg_read(ISR) & OVW)
355     {
356         unsigned char current;
357
358         // Select RTL8019AS register page 1.
359         ETHERDEV_SELECT_REG_PAGE(1);
360
361         // Retrieve current receive buffer page
362         current = etherdev_reg_read(CURR);
363
364         // Select RTL8019AS register page 1.
365         ETHERDEV_SELECT_REG_PAGE(0);
366
367         if (etherdev_reg_read(BNRY) == current)
368         {
369
370             leds1 = ~0x01;
371             leds2 = ~etherdev_reg_read(ISR);
372             sleep(5);
373             leds1 = ~0x02;
374             leds2 = ~etherdev_reg_read(BNRY);
375             sleep(5);
376             leds1 = ~0x04;
377             leds2 = ~current;
378             sleep(5);
379
380             etherdev_reset();
381         }
382     }
383     // Check if there is a packet in the rx buffer.
384     else if (etherdev_reg_read(ISR) & PRX)
385     {
386         unsigned int i;
387         unsigned char next_rx_packet;
388         unsigned char current;
389         unsigned char bnry;
390         unsigned char status;
391
392         // Retrieve packet header. (status, next_ptr, length_l, length_h)
393
394         // Set remote DMA start address registers to packet header.
395         bnry = etherdev_reg_read(BNRY) + 1;
396         if (bnry >= ETH_RX_PAGE_STOP)
397             bnry = ETH_RX_PAGE_START;
398         etherdev_reg_write(RSAR0, 0x00);
399         etherdev_reg_write(RSAR1, bnry);
400
401         // Select RTL8019AS register page 1.
402         ETHERDEV_SELECT_REG_PAGE(1);
403
404         // Retrieve current receive buffer page
405         current = etherdev_reg_read(CURR);
406
407         // Select RTL8019AS register page 1.
408         ETHERDEV_SELECT_REG_PAGE(0);
409
410         // Check if last packet has been removed from rx buffer.
411         if(bnry == current)
412         {
413             // Clear packet received interrupt flag.
414             etherdev_reg_write(ISR, PRX | RXE);
415             return 0;
416         }
417
418         // Set remote DMA byte count registers to packet header length.
419         etherdev_reg_write(RBCR0, 0x04);
420         etherdev_reg_write(RBCR1, 0x00);
421
422         // Clear remote DMA complete interrupt status register bit.
423         etherdev_reg_write(ISR, RDC);
424
425         // Initiate DMA transfer of packet header.
426         etherdev_reg_write(CR, READ | STA);
427
428         // Packet status.
429         status = etherdev_reg_read(RDMA);
430
431         // Save next packet pointer.
432         next_rx_packet = etherdev_reg_read(RDMA);
433
434         // Retrieve packet data length and subtract CRC bytes.
435         len =  etherdev_reg_read(RDMA);
436         len += etherdev_reg_read(RDMA) << 8;
437         len -= 4;
438
439         // Wait until remote DMA operation completes.
440         while(!(etherdev_reg_read(ISR) & RDC)) continue;
441
442         // Abort/ complete DMA operation.
443         etherdev_reg_write(CR, ABORT | STA);
444
445         // Limpia ISR
446         etherdev_reg_write(ISR, RDC);
447
448         // Si es un paquete inválido, lo dropeamos
449         if (len < 60 || len > 1518)
450         {
451             len = 0;
452             goto drop;
453         }
454
455         // Si hubo un error, también lo dropeamos
456         if ((status & 0x0F) != RXSOK)
457         {
458             len = 0;
459             goto drop;
460         }
461
462         // Retrieve packet data.
463
464         // Check if incoming packet will fit into rx buffer.
465         if(len <= sizeof(uip_buf))
466         {
467
468             // Set remote DMA start address registers to packet data.
469             etherdev_reg_write(RSAR0, 0x04);
470             etherdev_reg_write(RSAR1, bnry);
471
472             // Set remote DMA byte count registers to packet data length.
473             etherdev_reg_write(RBCR0, (unsigned char)(len & 0xFF));
474             etherdev_reg_write(RBCR1, (unsigned char)(len >> 8));
475
476             // Initiate DMA transfer of packet data.
477             etherdev_reg_write(CR, READ | STA);
478
479             // Read packet data directly into uip_buf.
480             uip_len = len;
481             for(i = 0; i < 14; i++)
482             {
483                 etherdev_reg_read(RDMA); // XXX descarto cabecera eth
484             }
485             for(i = 14; i < len; i++)
486             {
487                 uip_buf[i] = etherdev_reg_read(RDMA); // XXX copio el resto
488             }
489
490             // Wait until remote DMA operation complete.
491             while(!(etherdev_reg_read(ISR) & RDC)) continue;
492
493             // Abort/ complete DMA operation.
494             etherdev_reg_write(CR, ABORT | STA);
495
496             // Clear remote DMA complete interrupt status register bit.
497             etherdev_reg_write(ISR, RDC);
498
499         }
500         else
501         {
502             // Incoming packet too big, so dump it.
503             len = 0;
504         }
505
506 drop:
507         // Advance boundary pointer to next packet start.
508         etherdev_reg_write(BNRY, next_rx_packet - 1);
509
510     }
511
512     return len;
513 }
514