]> git.llucax.com Git - z.facultad/66.09/etherled.git/commitdiff
Primer intento de integración y creación del proyecto.
authorLeandro Lucarella <llucax@gmail.com>
Tue, 6 Dec 2005 07:58:21 +0000 (07:58 +0000)
committerLeandro Lucarella <llucax@gmail.com>
Tue, 6 Dec 2005 07:58:21 +0000 (07:58 +0000)
El programa es medio bobo, sólo recibe frames, los parsea (ethernet, ip, udp) y
muestra el payload de UDP. A pesar de esto no funciona, falta un poco de
debugging, pero como está basando en 2 grandes fragmentos que funcionaban por
separado, debería ser fácil ponerlo a andar.

21 files changed:
src/Makefile [new file with mode: 0644]
src/c/eth.c [deleted file]
src/c/ip.c [deleted file]
src/c/net.c [deleted file]
src/c/net.h [deleted file]
src/c/udp.c [deleted file]
src/config.h [new file with mode: 0644]
src/dp8390.c [new file with mode: 0644]
src/dp8390.h [new file with mode: 0644]
src/eth.c [new file with mode: 0644]
src/eth.h [moved from src/c/eth.h with 79% similarity]
src/etherled.Uv2 [new file with mode: 0644]
src/ip.c [new file with mode: 0644]
src/ip.h [moved from src/c/ip.h with 94% similarity]
src/main.c [new file with mode: 0644]
src/netdev.h [new file with mode: 0644]
src/reg51.h [new file with mode: 0644]
src/startup.a51 [new file with mode: 0644]
src/types.h [moved from src/c/types.h with 57% similarity]
src/udp.c [new file with mode: 0644]
src/udp.h [moved from src/c/udp.h with 80% similarity]

diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..9b5aa8b
--- /dev/null
@@ -0,0 +1,35 @@
+
+CC=sdcc
+
+LD=sdcc
+
+all: el.hex
+
+reg51.h: reg51sdcc.h
+
+netdev.h: types.h
+
+dp8390.h: types.h reg51.h netdev.h
+
+dp8390.rel: dp8390.c dp8390.h
+       $(CC) $(CFLAGS) -c dp8390.c
+
+eth.rel: eth.c eth.h netdev.h types.h
+       $(CC) $(CFLAGS) -c eth.c
+
+ip.rel: ip.c ip.h netdev.h types.h
+       $(CC) $(CFLAGS) -c ip.c
+
+udp.rel: udp.c udp.h ip.h netdev.h types.h
+       $(CC) $(CFLAGS) -c udp.c
+
+main.rel: main.c netdev.h eth.h ip.h udp.h
+       $(CC) $(CFLAGS) -c main.c
+
+el.hex: main.rel dp8390.rel eth.rel ip.rel udp.rel
+       $(LD) $(LDFLAGS) -o el.hex main.rel dp8390.rel eth.rel ip.rel udp.rel
+
+clean:
+       @rm -vf el.hex *.rel *.asm *.lst *.map *.lnk *.mem *.sym
+
+.PHONY: clean
diff --git a/src/c/eth.c b/src/c/eth.c
deleted file mode 100644 (file)
index 5c8686f..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "eth.h"
-
-/** tipos de paquetes transportados soportados */
-enum { IP = 0x0800, ARP = 0x0806 };
-
-byte mac_addr_local[MAC_ADDR_SIZE];
-
-byte mac_addr_remote[MAC_ADDR_SIZE];
-
-bool eth_frame_arp;
-
-bool eth_read_frame_header()
-{
-       /* variable para iterar */
-       byte i;
-       /* vemos si es para nosotros */
-       for (i = 0; i < MAC_ADDR_SIZE; ++i)
-               if (mac_addr_local[i] != net_getb())
-                       return false; /* no es para nosotros (drop) */
-       /* obtenemos MAC de origen */
-       for (i = 0; i < MAC_ADDR_SIZE; ++i)
-               mac_addr_remote[i] = net_getb();
-       /* obtenemos tipo de protocolo transportado por el frame, (sólo
-        * aceptamos IP y ARP) */
-       switch (net_getw())
-       {
-               case IP:
-                       eth_frame_arp = false;
-                       break;
-               case ARP:
-                       eth_frame_arp = true;
-                       break;
-               default:
-                       return false; /* drop */
-       }
-       return true;
-}
-
-void eth_write_frame_header()
-{
-       /* variable para iterar */
-       byte i;
-       /* mandamos como MAC de destino la remota */
-       for (i = 0; i < ETH_MAC_SIZE; ++i)
-               net_putb(mac_addr_remote[i]);
-       /* y como fuente la nuestra */
-       for (i = 0; i < ETH_MAC_SIZE; ++i)
-               net_putb(mac_addr_local[i]);
-       /* escribimos el tipo de paquete que transporta el frame */
-       net_putw(eth_frame_arp ? TYPE_ARP : TYPE_IP);
-}
-
diff --git a/src/c/ip.c b/src/c/ip.c
deleted file mode 100644 (file)
index 3f07cb2..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-#include "ip.h"
-
-/** protocolos soportados */
-enum { ICMP = 0x01, UDP = 0x11 };
-
-byte ip_addr_local[IP_ADDR_SIZE];
-
-byte ip_addr_remote[IP_ADDR_SIZE];
-
-byte ip_packet_len;
-
-bool ip_proto_icmp;
-
-/* para calcular checksum */
-uint16 checksum;
-
-/* agrega un word al checksum calculado */
-static void sum(uint16 w)
-{
-       checksum += w;
-       if (checksum < w) /* corrección de carry (hubo OV) */
-               ++checksum;
-}
-
-bool ip_read_packet_header()
-{
-       /* variables utilitarias (iterar y/o buffer) */
-       byte h, l;
-       /* reseteamos checksum */
-       checksum = 0;
-       /* versión y tamaño de cabecera vienen en el 1er byte */
-       h = net_getb();
-       /* sólo soportamos versión 4 */
-       if ((h >> 4) != 4)
-               return false; /* drop */
-       /* tamaño de cabecera */
-       if ((h & 0x0F) != 5) /* no aceptamos opciones raras =) */
-               return false; /* drop */
-       /* ignoramos el TOS y vamos calculando checksum */
-       sum(WORD(h, net_getb()));
-       /* obtenemos tamaño del paquete */
-       if (h = net_getb()) /* tiene más de 255 bytes (no lo soportamos) */
-               return false; /* drop */
-       ip_packet_len = net_getb(); /* hasta 255 bytes tienen los nuestros */
-       /* vamos calculando checksum */
-       sum(WORD(h, ip_packet_len));
-       /* ignoramos identificación (2 bytes) y vamos calculando checksum */
-       sum(net_getw());
-       /* si tiene prendido el bit de MF (More Fragments, bit 5 del byte, bit 2
-        * de los flags de la cabecera) o si tiene un offset de fragmento (bits
-        * del 4 al 0 y todos los bits del byte siguiente), dropeamos (no
-        * soportamos fragmentación) */
-       h = net_getb();
-       l = net_getb();
-       if ((h & 0x3F) || l)
-               return false; /* drop */
-       /* seguimos calculando checksum */
-       sum(WORD(h, l));
-       /* no le damos bola al TTL (no le vamos a hacer lío si ya llegó hasta
-        * acá el pobre =) */
-       h = net_getb();
-       /* protocolo (sólo soportamos UDP e ICMP) */
-       l = net_getb();
-       switch (l)
-       {
-               case ICMP:
-                       ip_proto_icmp = true;
-                       break;
-               case UDP:
-                       ip_proto_icmp = false;
-                       break;
-               default:
-                       return false; /* drop */
-       }
-       /* sigo calculando checksum */
-       sum(WORD(h, l));
-       /* obtenemos checksum y seguimos el cálculo */
-       sum(net_getw());
-       /* obtenemos IP de origen (mientras seguimos calculando el checksum) */
-       for (l = 0; l < IP_ADDR_SIZE; ++l)
-       {
-               ip_addr_remote[l] = net_getb();
-               if (l % 2)
-                       sum(WORD(h, ip_addr_remote[l]));
-               else
-                       h = ip_addr_remote[l];
-       }
-       /* vemos si el paquete es para nosotros (ningún soportar broadcast =)
-        * (mientras seguimos calculando el checksum) */
-       for (l = 0; l < IP_ADDR_SIZE; ++l)
-       {
-               if (ip_addr_local[l] != net_getb()) 
-                       return false; /* drop (no es para nosotros) */
-               if (l % 2)
-                       sum(WORD(h, ip_addr_local[l]));
-               else
-                       h = ip_addr_local[l];
-       }
-       /* verificamos checksum */
-       if (~checksum)
-               return false; /* checksum malo, drop */
-       return true;
-}
-
-void ip_write_packet_header()
-{
-       /* variables utilitarias (iterar y/o buffer) */
-       byte h, l;
-       /* identificador del paquete IP (incrementa con cada paquete) */
-       static uint16 id;
-       /* reseteamos checksum */
-       checksum = 0;
-       /* versión (4) y tamaño de cabecera (5 words de 4 bytes = 20 bytes) */
-       net_putb(h = 0x45);
-       /* TOS (0xc0 = Internetwork Control, 0x00 = normal) */
-       l = ip_proto_icmp ? 0xc0 : 0x00;
-       net_putb(l);
-       sum(WORD(h, l)); /* actualizamos checksum */
-       /* escribimos tamaño del paquete */
-       net_putb(h = 0x00); /* nunca vamos a mandar algo de más de 255 bytes */
-       net_putb(ip_packet_len);
-       sum(WORD(h, ip_packet_len)); /* actualizamos checksum */
-       /* identificación (sirve para reensamblar paquetes) */
-       net_putw(id);
-       sum(id); /* actualizamos checksum */
-       /* pedimos que no se fragmente */
-       net_putb(h = 0x40); /* Don't Fragment (DF) = 1 */
-       net_putb(l = 0x00); /* offset de fragmento = 0 */
-       sum(WORD(h, l)); /* actualizamos checksum */
-       /* TTL de 64 saltos porque está de moda */
-       net_putb(h = 0x40);
-       /* protocolo (sólo soportamos UDP e ICMP) */
-       l = ip_proto_icmp ? ICMP : UDP;
-       net_putb(l);
-       sum(WORD(h, l)); /* actualizamos checksum */
-       /* checksum: antes de poder escribir el checksum hay que terminar de
-        * calcularlo según las direcciones IP de origen y destino, así que eso
-        * hacemos */
-       for (l = 0; l < IP_ADDR_SIZE; ++l) /* origen = local */
-               if (l % 2)
-                       sum(WORD(h, ip_addr_local[l]));
-               else
-                       h = ip_addr_local[l];
-       for (l = 0; l < IP_ADDR_SIZE; ++l) /* destino = remota */
-               if (l % 2)
-                       sum(WORD(h, ip_addr_remote[l]));
-               else
-                       h = ip_addr_remote[l];
-       /* ahora sí grabamos el checksum */
-       net_putw(~checksum);
-       /* ahora sí, continuamos poniendo las direcciones */
-       /* ponemos como dirección IP de origen la nuestra */
-       for (i = 0; i < IP_ADDR_SIZE; ++i)
-               net_putb(ip_addr_local[i]);
-       /* IP de destino, la remota */
-       for (i = 0; i < IP_ADDR_SIZE; ++i)
-               net_putb(ip_addr_remote[i]);
-}
-
diff --git a/src/c/net.c b/src/c/net.c
deleted file mode 100644 (file)
index 599e26d..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "net.h"
-
-uint16 net_getw()
-{
-       byte b = net_getb() << 8;
-       return b + net_getb();
-}
-
-void net_putw(uint16 w)
-{
-       net_putb(HIGH(w));
-       net_putb(LOW(w));
-}
-
diff --git a/src/c/net.h b/src/c/net.h
deleted file mode 100644 (file)
index 678513a..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _NET_H_
-#define _NET_H_
-
-#include "types.h"
-
-/** lee un byte de la placa de red */
-byte net_getb();
-
-/** escribe un byte a la placa de red */
-void net_putb(byte);
-
-/** lee un word de la placa de red */
-uint16 net_getw();
-
-/** escribe un word a la placa de red */
-void net_putw(uint16);
-
-#endif /* _NET_H_ */
diff --git a/src/c/udp.c b/src/c/udp.c
deleted file mode 100644 (file)
index c6fbfcc..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "ip.h"
-#include "udp.h"
-
-uint16 udp_port_local;
-
-uint16 udp_port_remote;
-
-byte udp_dgram_len;
-
-/* para calcular checksum */
-uint16 checksum;
-
-/* agrega un word al checksum calculado */
-void udp_checksum_sum(uint16 w)
-{
-       checksum += w;
-       if (checksum < w) /* corrección de carry (hubo OV) */
-               ++checksum;
-}
-
-/* indica si el checksum calculado está ok */
-bool udp_checksum_ok()
-{
-       return ~checksum;
-}
-
-bool udp_read_dgram_header()
-{
-       /* reseteamos checksum */
-       checksum = 0;
-       /* el UDP tiene un checksum que incluye parte de la cabecera IP */
-       /* ip de origen */
-       udp_checksum_sum(WORD(ip_addr_remote[0], ip_addr_remote[1]));
-       udp_checksum_sum(WORD(ip_addr_remote[2], ip_addr_remote[3]));
-       /* ip de destino */
-       udp_checksum_sum(WORD(ip_addr_local[0], ip_addr_local[1]));
-       udp_checksum_sum(WORD(ip_addr_local[2], ip_addr_local[3]));
-       /* protocolo expresado en 16 bits (0x11 es UDP) */
-       udp_checksum_sum(0x11);
-       /* tamaño del paquete UDP (sin las cabeceras que son 20 bytes) */
-       udp_checksum_sum(ip_packet_len - 20);
-       /* de ahora en más todos los datos del checksum corresponden a UDP */
-       /* puerto origen (remoto) */
-       udp_port_remote = net_getw();
-       /* agregamos puerto de origen al checksum */
-       udp_checksum_sum(udp_port_remote);
-       /* sólo aceptamos datagramas a nuestro puerto */
-       if (net_getw() != udp_port_local)
-               return false; /* drop */
-       /* agregamos puerto de destino al checksum */
-       udp_checksum_sum(udp_port_local);
-       /* tamaño del datagrama */
-       if (net_getb()) /* no soportamos más de 255 bytes */
-               return false; /* drop */
-       udp_dgram_len = net_getb();
-       /* agregamos tamaño al checksum */
-       udp_checksum_sum(udp_dgram_len);
-       /* agregamos checksum al checksum */
-       udp_checksum_sum(net_getw());
-       /* falta agregar el cuerpo del mensaje para verificar la suma
-        * esto debe hacerlo el protocolo que sigue para poder seguir obteniendo
-        * los datos de la placa de red byte a byte */
-       return true;
-}
-
-void udp_write_dgram_header()
-{
-       /* puerto origen */
-       net_putw(udp_port_local);
-       /* puerto destino */
-       net_putw(udp_port_remote);
-       /* tamaño del datagrama */
-       net_putb(0x00); /* parte alta en 0 porque no soportamos más de 255 */
-       net_putb(udp_dgram_len);
-       /* indicamos que no se usa checksum */
-       net_putw(0x0000);
-       return true;
-}
-
diff --git a/src/config.h b/src/config.h
new file mode 100644 (file)
index 0000000..71f1727
--- /dev/null
@@ -0,0 +1,10 @@
+// vim: set et sw=4 sts=4 :    
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#define NET_RECV_CALLBACK eth_recv
+
+#define 
+
+#endif // _CONFIG_H_
diff --git a/src/dp8390.c b/src/dp8390.c
new file mode 100644 (file)
index 0000000..6392307
--- /dev/null
@@ -0,0 +1,477 @@
+// vim: set et sw=4 sts=4 :    
+
+#include "eth.h"
+#include "dp8390.h"
+
+#ifdef DEBUG
+void sleep(unsigned char);
+#ifdef SDCC
+static xdata at 0x0080 byte leds0;
+static xdata at 0x00c0 byte leds1;
+#else
+static byte xdata leds0 _at_ 0x0080;
+static byte xdata leds1 _at_ 0x00c0;
+#endif
+#endif
+
+/// Datos persistentes del módulo
+static union
+{
+    byte send_len; ///> Tamaño del frame que será enviado
+    byte next_pkt; ///> Próximo frame a obtener
+}
+persistent;
+
+/// Cambia de página sin modificar los demás bits del CR
+#define SELECT_REG_PAGE(page)                         \
+    do                                                \
+    {                                                 \
+        write_reg(CR, read_reg(CR) & ~(PS1 | PS0));   \
+        write_reg(CR, read_reg(CR) | (page << 6));    \
+    }                                                 \
+    while (0)
+
+/// Aborta (o completa) el DMA limpiando el ISR
+#define ABORT_DMA(flags)        \
+    do                          \
+    {                           \
+        write_reg(CR, flags);   \
+        write_reg(ISR, RDC);    \
+    }                           \
+    while (0)
+
+
+static void write_reg(unsigned char reg, unsigned char wr_data)
+{
+    // Select register address.
+    ADDR_PORT &= ~ADDR_PORT_MASK; 
+    ADDR_PORT |= reg;
+
+    // Output register data to port.
+    DATA_PORT = wr_data;
+
+    // Clock register data into RTL8019AS.
+    // IOR & IOW are both active low.
+    NICE = 0;
+    IOW = 0;
+    IOW = 1;
+    NICE = 1;
+
+    // Set register data port as input again.
+    DATA_PORT = DATA_PORT_MASK;
+} 
+
+
+static unsigned char read_reg(unsigned char reg)
+{
+    // Select register address.
+    ADDR_PORT &= ~ADDR_PORT_MASK;
+    ADDR_PORT |= reg;
+
+    // Enable register data output from RTL8019AS.
+    NICE = 0;
+    IOR = 0;
+
+    // Read register data from port.
+    reg = DATA_PORT;
+
+    // Disable register data output from RTL8019AS.
+    IOR = 1; 
+    NICE = 1;   
+
+    return reg;
+} 
+
+/** Resetea placa de red en caso de buffer overflow */
+static void reset()
+{
+    bit retransmit = read_reg(CR) & TXP;
+
+    // If the receive buffer ring has overflowed we dump the whole
+    // thing and start over. There is no way of knowing whether the
+    // data it contains is uncorrupted, or will cause us grief.
+
+    // Stop RTL8019AS and abort DMA operation.
+    write_reg(CR, STOP);
+
+    // Wait for controller to halt after any current tx completes.
+    while(!(read_reg(ISR) & RST)) continue;
+
+    // Reset remote byte count registers.
+    write_reg(RBCR0, 0x00);
+    write_reg(RBCR1, 0x00);
+
+    // Check whether currently transmitting a packet.
+    if(retransmit)
+    {
+        // If neither a successful transmission nor a tx abort error 
+        // has occured, then flag current tx packet for resend.
+        if(read_reg(ISR) & (PTX | TXE))
+        {
+            retransmit = 0;
+        }
+    }
+
+    // Set transmit configuration register to loopback internally.
+    write_reg(TCR, MODE1);
+
+    // Restart the RTL8019AS.
+    write_reg(CR, START);
+
+    // Re-initialise last receive buffer read pointer.
+    write_reg(BNRY, RX_PAGE_START);
+
+    // Select RTL8019AS register page 1.
+    SELECT_REG_PAGE(1);
+
+    // Re-initialise current packet receive buffer page pointer.
+    write_reg(CURR, RX_PAGE_START + 1);
+
+    // Select RTL8019AS register page 0.
+    SELECT_REG_PAGE(0);
+
+    // Clear rx buffer overflow & packet received interrupt flags.
+    write_reg(ISR, PRX | OVW);
+
+    // Re-itialise transmit configuration reg for normal operation.
+    write_reg(TCR, MODE0);
+
+    if(retransmit)
+    {
+        // Retransmit packet in RTL8019AS local tx buffer.
+        write_reg(CR, START | TXP);
+    }
+}
+
+
+/** Inicializa dispositivo de red
+ * @return true si se inicializó correctamente, false si no
+ */
+bool netdev_init()
+{
+    // Set IOR & IOW as they're active low.
+    IOR = 1;
+    IOW = 1;
+    NICE = 1;
+
+    // Set register data port as input.
+    DATA_PORT = DATA_PORT_MASK;
+
+    // Configure RTL8019AS ethernet controller.
+
+    // Keil startup code takes 4ms to execute (18.432MHz, X1 mode).
+    // That leaves plenty of time for the RTL8019AS to read it's
+    // configuration in from the 9346 EEPROM before we get here.
+
+    // Select RTL8019AS register page 0.
+    SELECT_REG_PAGE(0);
+
+    // Check if RTL8019AS fully reset.
+    if(!(read_reg(ISR) & RST))
+    {
+        return 0;
+    }
+
+    // Stop RTL8019AS, select page 0 and abort DMA operation.
+    write_reg(CR, STOP);
+
+    // Initialise data configuration register. 
+    // FIFO threshold 8 bytes, no loopback, don't use auto send packet.
+    write_reg(DCR, FT1 | LS);
+
+    // Reset remote byte count registers.
+    write_reg(RBCR0, 0u);
+    write_reg(RBCR1, 0u);
+
+    // Receive configuration register to monitor mode.
+    write_reg(RCR, MON);
+
+    // Initialise transmit configuration register to loopback internally.
+    write_reg(TCR, MODE1);
+
+    // Clear interrupt status register bits by writing 1 to each.
+    write_reg(ISR, ALL);
+
+    // Mask all interrupts in mask register.
+    write_reg(IMR, NONE);
+
+    // Obtengo MAC de la placa
+    write_reg(RBCR0, 12u); // Vamos a leer 12 bytes (2 x 6)
+    write_reg(RBCR1, 0u); 
+    write_reg(RSAR0, 0u); // En la dirección 0x0000
+    write_reg(RSAR1, 0u);
+    write_reg(CR, READ); // Comienza lectura
+    eth_addr_local[0] = read_reg(RDMA);
+    read_reg(RDMA); // Ignoramos porque viene como un word
+    eth_addr_local[1] = read_reg(RDMA);
+    read_reg(RDMA); // Ignoramos porque viene como un word
+    eth_addr_local[2] = read_reg(RDMA);
+    read_reg(RDMA); // Ignoramos porque viene como un word
+    eth_addr_local[3] = read_reg(RDMA);
+    read_reg(RDMA); // Ignoramos porque viene como un word
+    eth_addr_local[4] = read_reg(RDMA);
+    read_reg(RDMA); // Ignoramos porque viene como un word
+    eth_addr_local[5] = read_reg(RDMA);
+    read_reg(RDMA); // Ignoramos porque viene como un word
+
+    // Abort/ complete DMA operation.
+    ABORT_DMA(STOP);
+
+    // Set transmit page start.
+    write_reg(TPSR, TX_PAGE_START);
+
+    // Set receive buffer page start.
+    write_reg(PSTART, RX_PAGE_START);
+
+    // Initialise last receive buffer read pointer.
+    write_reg(BNRY, RX_PAGE_START);
+
+    // Set receive buffer page stop.
+    write_reg(PSTOP, RX_PAGE_STOP);
+
+    // Select RTL8019AS register page 1.
+    SELECT_REG_PAGE(1);
+
+    // Initialise current packet receive buffer page pointer
+    write_reg(CURR, RX_PAGE_START + 1);
+
+    // Set physical address
+    write_reg(PAR0, eth_addr_local[0]);
+    write_reg(PAR1, eth_addr_local[1]);
+    write_reg(PAR2, eth_addr_local[2]);
+    write_reg(PAR3, eth_addr_local[3]);
+    write_reg(PAR4, eth_addr_local[4]);
+    write_reg(PAR5, eth_addr_local[5]);
+
+    // Restart RTL8019AS. 
+    write_reg(CR, START);
+
+    // Initialise transmit configuration register for normal operation.
+    write_reg(TCR, MODE0);
+
+    // Receive configuration register to accept broadcast packets.
+    write_reg(RCR, AB);
+
+    return 1;
+}
+
+
+/** Comienza el envío de un nuevo frame
+ * @param len Tamaño del frame a enviar
+ */
+void netdev_send_start()
+{
+    persistent.send_len = 0;
+    // Wait until pending transmit operation completes.
+    while(read_reg(CR) & TXP) continue;
+
+    // Set remote DMA start address registers to indicate where to load packet.
+    write_reg(RSAR0, 0u);
+    write_reg(RSAR1, TX_PAGE_START);
+
+    // Set remote DMA byte count registers to indicate length of packet load.
+    write_reg(RBCR0, MAX_PACKET_LEN); // Tamaño máximo en principio
+    write_reg(RBCR1, 0u);
+
+    // Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS.
+    write_reg(CR, WRITE | STA);
+}
+
+/** Escribe un byte al buffer de la placa de red para ser enviado
+ * @precond netdev_send_start() debe haber sido ejecutada
+ * @param b Byte a enviar
+ */
+void netdev_send_byte(byte b)
+{
+    persistent.send_len++;
+    write_reg(RDMA, b);
+}
+
+/** Escribe un word al buffer de la placa de red para ser enviado
+ * @precond netdev_send_start() debe haber sido ejecutada
+ * @param w Word a enviar
+ */
+void netdev_send_word(uint16 w)
+{
+    persistent.send_len += 2;
+    write_reg(RDMA, HIGH(w));
+    write_reg(RDMA, LOW(w));
+}
+
+/** Finaliza el envío del frame
+ * @precond netdev_send_start() debe haber sido ejecutada
+ */
+void netdev_send_end()
+{
+    // Abort/ complete DMA operation.
+    ABORT_DMA(START);
+
+    // Set transmit page start to indicate packet start.
+    write_reg(TPSR, TX_PAGE_START);
+
+    // Ethernet packets must be > 60 bytes, otherwise are rejected as runts.
+    if (persistent.send_len < MIN_PACKET_LEN)
+    {
+        persistent.send_len = MIN_PACKET_LEN;
+    }
+
+    // Set transmit byte count registers to indicate packet length.
+    write_reg(TBCR0, LOW(persistent.send_len));
+    write_reg(TBCR1, 0u);
+
+    // Issue command for RTL8019AS to transmit packet from it's local buffer.
+    write_reg(CR, START | TXP);
+}
+
+/** Comienza la lectura de un nuevo frame
+ * @return Cantidad de bytes del frame leído
+ */
+byte netdev_recv_start()
+{    
+    // Check if the rx buffer has overflowed.
+    if (read_reg(ISR) & OVW)
+    {
+        byte current;
+
+        // Select RTL8019AS register page 1.
+        SELECT_REG_PAGE(1);
+
+        // Retrieve current receive buffer page
+        current = read_reg(CURR);
+
+        // Select RTL8019AS register page 1.
+        SELECT_REG_PAGE(0);
+
+        if (read_reg(BNRY) == current)
+        {
+#ifdef DEBUG
+            leds1 = ~0x01;
+            leds2 = ~read_reg(ISR);
+            sleep(5);
+            leds1 = ~0x02;
+            leds2 = ~read_reg(BNRY);
+            sleep(5);
+            leds1 = ~0x04;
+            leds2 = ~current;
+            sleep(5);
+#endif
+            reset();
+        }
+        return 0u;
+    }
+    // Check if there is a packet in the rx buffer.
+    else if (read_reg(ISR) & PRX)
+    {
+        struct buf_hdr_t
+        {
+            byte status;    // Estado del frame recibido
+            byte next;      // Offset del próximo frame
+            uint16 len;     // Tamaño del frame
+        }
+        buf_hdr;
+        byte current;
+        byte bnry;
+
+        // Retrieve packet header. (status, next_ptr, length_l, length_h)
+
+        // Set remote DMA start address registers to packet header.
+        bnry = read_reg(BNRY) + 1;
+        if (bnry >= RX_PAGE_STOP)
+            bnry = RX_PAGE_START;
+        write_reg(RSAR0, 0u);
+        write_reg(RSAR1, bnry);
+
+        // Select RTL8019AS register page 1.
+        SELECT_REG_PAGE(1);
+
+        // Retrieve current receive buffer page
+        current = read_reg(CURR);
+
+        // Select RTL8019AS register page 1.
+        SELECT_REG_PAGE(0);
+
+        // Check if last packet has been removed from rx buffer.
+        if(bnry == current)
+        {
+            // Clear packet received interrupt flag.
+            write_reg(ISR, PRX | RXE);
+            return 0u;
+        }
+
+        // Set remote DMA byte count registers to packet header length.
+        write_reg(RBCR0, sizeof(struct buf_hdr_t));
+        write_reg(RBCR1, 0u);
+
+        // Clear remote DMA complete interrupt status register bit.
+        write_reg(ISR, RDC);
+
+        // Initiate DMA transfer of packet header.
+        write_reg(CR, READ);
+
+        // Packet status.
+        buf_hdr.status = read_reg(RDMA);
+
+        // Save next packet pointer.
+        buf_hdr.next = persistent.next_pkt = read_reg(RDMA);
+
+        // Retrieve packet data length and subtract CRC bytes.
+        buf_hdr.len = read_reg(RDMA) - sizeof(struct buf_hdr_t);
+
+        // Si es muy grande, muy chico o hubo error, lo descartamos
+        if ((buf_hdr.len < MIN_PACKET_LEN) || (buf_hdr.len > MAX_PACKET_LEN)
+                || ((buf_hdr.status & 0x0F) != RXSOK)
+                || read_reg(RDMA)) // Parte alta del tamaño
+        {
+            ABORT_DMA(START); // Termina DMA
+            write_reg(BNRY, buf_hdr.next - 1); // Pasa al próximo frame
+            return 0;
+        }
+
+        // Abort/ complete DMA operation.
+        ABORT_DMA(START);
+
+        // Set remote DMA start address registers to packet data.
+        write_reg(RSAR0, sizeof(struct buf_hdr_t));
+        write_reg(RSAR1, bnry);
+
+        // Set remote DMA byte count registers to packet data length.
+        write_reg(RBCR0, buf_hdr.len);
+        write_reg(RBCR1, 0u);
+
+        // Initiate DMA transfer of packet data.
+        write_reg(CR, READ);
+
+        return buf_hdr.len;
+    }
+    return 0;
+}
+
+/** Lee un byte del buffer de la placa de red
+ * @precond netdev_recv_start() debe haber sido ejecutada
+ */
+byte netdev_recv_byte()
+{
+    return read_reg(RDMA);
+}
+
+/** Lee un word del buffer de la placa de red
+ * @precond netdev_recv_start() debe haber sido ejecutada
+ */
+uint16 netdev_recv_word()
+{
+    uint16 w = netdev_recv_byte() << 8;
+    return w + netdev_recv_byte();
+}
+
+/** Finaliza la lectura del frame
+ * @precond netdev_recv_start() debe haber sido ejecutada
+ */
+void netdev_recv_end()
+{
+    // Abort/ complete DMA operation.
+    ABORT_DMA(START);
+
+    // Advance boundary pointer to next packet start.
+    write_reg(BNRY, persistent.next_pkt - 1);
+}
+
diff --git a/src/dp8390.h b/src/dp8390.h
new file mode 100644 (file)
index 0000000..0d2fa39
--- /dev/null
@@ -0,0 +1,235 @@
+// vim: set et sw=4 sts=4 :    
+
+#ifndef _DP8390_H_
+#define _DP8390_H_
+
+#include "reg51.h"
+#include "types.h"
+#include "netdev.h"
+
+// Configuración de puertos para comunicarse con la placa de red
+#define DATA_PORT       P2      // Adjust this to suit hardware.
+#define DATA_PORT_MASK  0xFF    // Máscara para leer del puerto
+#define ADDR_PORT       P1      // Adjust this to suit hardware.
+#define ADDR_PORT_MASK  0x1F    // Máscara de direcciones (para no cambiar
+                                // bits que no se usan)
+#ifdef SDCC
+sbit at 0xB2 IOW;   // ISA slot pin B13, RTL8019AS pin 30, active low
+sbit at 0xB5 IOR;   // ISA slot pin B14, RTL8019AS pin 29, active low
+sbit at 0xB2 NICE;  // A7, usado para activar placa de red
+#else
+#define CTRL_PORT       P3  // Adjust this to suit hardware.
+sbit IOW = CTRL_PORT^4;     // ISA slot pin B13, RTL8019AS pin 30, active low
+sbit IOR = CTRL_PORT^5;     // ISA slot pin B14, RTL8019AS pin 29, active low
+sbit NICE = CTRL_PORT^2;    // A7, usado para activar placa de red
+#endif
+
+// Configuración de paǵinas de buffers
+#define TX_PAGE_START  0x40      // 0x4000 Tx buffer:  6 * 256 = 1536 bytes
+#define RX_PAGE_START  0x46      // 0x4600 Rx buffer: 26 * 256 = 6656 bytes
+#define RX_PAGE_STOP   0x60      // 0x6000
+
+// Límites de tamaño de paquete
+#define MIN_PACKET_LEN 60u  // Mínimo permitido por 802.3
+#define MAX_PACKET_LEN 128u // Mínimo permitido por nuestra escasa memoria =)
+
+// Register base address
+#define REG_BASE 0x0000 // Hardwired to 0x0300
+
+// Registers common to all pages.
+#define CR           REG_BASE + 0x00   // Control register
+    // Control register bits
+    #define PS1      0x80                  // Page select bit 1
+    #define PS0      0x40                  // Page select bit 0
+    #define RD2      0x20                  // Remote DMA control bit 2
+    #define RD1      0x10                  // Remote DMA control bit 1
+    #define RD0      0x08                  // Remote DMA control bit 0
+    #define TXP      0x04                  // Transmit packet bit
+    #define STA      0x02                  // Start bit (a flag only)
+    #define STP      0x01                  // Stop bit transceiver ctrl
+    // Shortcuts
+    #define PAGE0    0x00                  // Page 0
+    #define PAGE1    0x40                  // Page 1
+    #define PAGE2    0x80                  // Page 2
+    #define PAGE3    0xC0                  // Page 3 (Reserved!)
+    #define ABORT    0x20                  // Abort/Complete DMA
+    #define READ     0x0A                  // Remote Read (RD0 | STA)
+    #define WRITE    0x12                  // Remote Write (RD1 | STA)
+    #define SENDPKT  0x1A                  // Send Packet (RD0 | RD1 | STA)
+    #define STOP     0x21                  // STP | ABORT
+    #define START    0x22                  // STA | ABORT
+
+#define RDMA         0x10                  // Remote DMA port
+#define RESET        0x18                  // Reset port
+
+// Page 0 read/write registers.
+#define BNRY         REG_BASE + 0x03   // Boundary register
+#define ISR          REG_BASE + 0x07   // Interrupt status register
+    // Interrupt status register bits
+    #define RST      0x80                  // Reset state indicator bit
+    #define RDC      0x40                  // Remote DMA complete bit
+    #define CNT      0x20                  // Network tally counter MSB set
+    #define OVW      0x10                  // Receive buffer exhausted
+    #define TXE      0x08                  // Transmit abort error bit
+    #define RXE      0x04                  // Receive error report bit
+    #define PTX      0x02                  // Successful packet transmit
+    #define PRX      0x01                  // Successful packet receive
+    // Shortcuts
+    #define ALL     0xFF                  // Todos los bits
+    #define NONE    0x00                  // Ninguno
+
+// Page 0 read only registers.
+#define CLDA0        REG_BASE + 0x01
+#define CLDA1        REG_BASE + 0x02
+#define TSR          REG_BASE + 0x04
+#define NCR          REG_BASE + 0x05
+#define FIFO         REG_BASE + 0x06
+#define CRDA0        REG_BASE + 0x08
+#define CRDA1        REG_BASE + 0x09
+#define CONFIGA      REG_BASE + 0x0A
+#define CONFIGB      REG_BASE + 0x0B
+#define RSR          REG_BASE + 0x0C
+#define CNTR0        REG_BASE + 0x0D
+#define CNTR1        REG_BASE + 0x0E
+#define CNTR2        REG_BASE + 0x0F
+
+// Page 0 write only registers.
+#define PSTART       REG_BASE + 0x01   // Receive page start register
+#define PSTOP        REG_BASE + 0x02   // Receive page stop register
+#define TPSR         REG_BASE + 0x04   // Transmit page start register
+#define TBCR0        REG_BASE + 0x05   // Transmit byte count register 0
+#define TBCR1        REG_BASE + 0x06   // Transmit byte count register 1
+#define RSAR0        REG_BASE + 0x08   // Remote start address register 0
+#define RSAR1        REG_BASE + 0x09   // Remote start address register 0
+#define RBCR0        REG_BASE + 0x0A   // Remote byte count register 0
+#define RBCR1        REG_BASE + 0x0B   // Remote byte count register 1
+#define RCR          REG_BASE + 0x0C   // Receive configuration register
+    // Receive configuration register bits (write in page 0, read in page 2)
+    #define MON      0x20                  // Monitor mode select bit
+    #define PRO      0x10                  // Promiscuous mode select bit
+    #define AM       0x08                  // Multicast packet accept bit
+    #define AB       0x04                  // Broadcast packet accept bit
+    #define AR       0x02                  // Runt packet accept bit
+    #define SEP      0x01                  // Error packet accept bit
+#define TCR          REG_BASE + 0x0D   // Transmit configuration register
+    // Transmit configuration register bits
+    #define OFST     0x10                  // Collision offset enable bit
+    #define ATD      0x08                  // Auto transmit disable select bit
+    #define LB1      0x04                  // Loopback mode select bit 1
+    #define LB0      0x02                  // Loopback mode select bit 0
+    #define CRC      0x01                  // CRC generation inhibit bit
+    // Shortcuts
+    #define MODE0    0x00                  // Loopback mode 0
+    #define MODE1    0x02                  // Loopback mode 1
+    #define MODE2    0x04                  // Loopback mode 2
+    #define MODE3    0x06                  // Loopback mode 3
+#define DCR          REG_BASE + 0x0E   // Data configuration register
+    // Data configuration register bits (write in page 0, read in page 2)
+    #define FT1      0x40                  // FIFO threshold select bit 1
+    #define FT0      0x20                  // FIFO threshold select bit 0
+    #define ARM      0x10                  // Auto-initialise remote
+    #define LS       0x08                  // Loopback select bit
+    #define LAS      0x04                  // Set to 0 (pwrup = 1)
+    #define BOS      0x02                  // Byte order select bit
+    #define WTS      0x01                  // Word transfer select bit
+#define IMR          REG_BASE + 0x0F   // Interrupt mask register
+    // Interrupt mask register bits
+    // Each enable bit correspons with an interrupt flag in ISR
+
+// Page 1 read/write registers.
+#define PAR0         REG_BASE + 0x01   // Physical address register 0
+#define PAR1         REG_BASE + 0x02   // Physical address register 1
+#define PAR2         REG_BASE + 0x03   // Physical address register 2
+#define PAR3         REG_BASE + 0x04   // Physical address register 3
+#define PAR4         REG_BASE + 0x05   // Physical address register 4
+#define PAR5         REG_BASE + 0x06   // Physical address register 5
+#define CURR         REG_BASE + 0x07   // Current receive buffer page
+#define MAR0         REG_BASE + 0x08
+#define MAR1         REG_BASE + 0x09
+#define MAR2         REG_BASE + 0x0A
+#define MAR3         REG_BASE + 0x0B
+#define MAR4         REG_BASE + 0x0C
+#define MAR5         REG_BASE + 0x0D
+#define MAR6         REG_BASE + 0x0E
+#define MAR7         REG_BASE + 0x0F
+
+// Page 2 read only registers.
+// Each previously defined in page 0 write only.
+//#define PSTART     REG_BASE + 0x01
+//#define PSTOP      REG_BASE + 0x02
+//#define TPSR       REG_BASE + 0x04
+//#define RCR        REG_BASE + 0x0C
+//#define TCR        REG_BASE + 0x0D
+//#define DCR        REG_BASE + 0x0E
+//#define IMR        REG_BASE + 0x0F
+
+// Page 3 read/write registers.
+#define _9346CR      REG_BASE + 0x01   // 9346 EEPROM command register
+    // 9346 EEPROM command register bits
+    #define EEM1     0x80                  // RTL8019AS operating mode bit 1
+    #define EEM0     0x40                  // RTL8019AS operating mode bit 0
+    #define EECS     0x08                  // 9346 EEPROM chip select bit
+    #define EESK     0x04                  // 9346 EEPROM serial clock bit
+    #define EEDI     0x02                  // 9346 EEPROM data input bit
+    #define EEDO     0x01                  // 9346 EEPROM data output bit
+#define BPAGE        REG_BASE + 0x02
+#define CONFIG1      REG_BASE + 0x04   // RTL9019AS config register 1
+    // RTL9019AS config register 1 bits
+    #define IRQEN    0x80                  // IRQ enable bit (WR protected)
+    #define IRQS2    0x40                  // IRQ line select bit 2
+    #define IRQS1    0x20                  // IRQ line select bit 1
+    #define IRQS0    0x10                  // IRQ line select bit 0
+    #define IOS3     0x08                  // I/O base address select bit 3
+    #define IOS2     0x04                  // I/O base address select bit 2
+    #define IOS1     0x02                  // I/O base address select bit 1
+    #define IOS0     0x01                  // I/O base address select bit 0
+#define CONFIG2      REG_BASE + 0x05   // 
+    // RTL9019AS config register 2 bits
+    #define PL1      0x80                  // Network medium type select bit 1
+    #define PL0      0x40                  // Network medium type select bit 0
+    #define BSELB    0x20                  // Boot ROM disable (WR protected)
+    #define BS4      0x10                  // Boot ROM configuration bit 4
+    #define BS3      0x08                  // Boot ROM configuration bit 3
+    #define BS2      0x04                  // Boot ROM configuration bit 2
+    #define BS1      0x02                  // Boot ROM configuration bit 1
+    #define BS0      0x01                  // Boot ROM configuration bit 0
+#define CONFIG3      REG_BASE + 0x06   // RTL9019AS config register 3
+    // RTL9019AS config register 3 bits
+    #define PNP      0x80                  // Plug & play mode indicator bit
+    #define FUDUP    0x40                  // Full duplex mode select bit
+    #define LEDS1    0x20                  // LED output select bit 1
+    #define LEDS0    0x10                  // LED output select bit 0
+    #define SLEEP    0x04                  // Sleep mode select bit
+    #define PWRDN    0x02                  // Power down mode select bit
+    #define ACTIVEB  0x01                  // Inverse of bit 0, PNP active reg
+
+// Page 3 read only registers.
+#define CONFIG0      REG_BASE + 0x03   // RTL9019AS config register 0
+    // RTL9019AS config register 0 bits
+    #define VERID1   0x80                  // RTL9019AS version ID bit 1 (R/W)
+    #define VERID0   0x40                  // RTL9019AS version ID bit 0 (R/W)
+    #define AUI      0x20                  // AUI input pin state bit
+    #define PNPJP    0x10                  // PNP jumper pin state bit
+    #define JP       0x08                  // JP input pin state bit
+    #define BNC      0x04                  // Thinnet mode indication bit
+#define CSNSAV       REG_BASE + 0x08
+#define INTR         REG_BASE + 0x0B
+#define CONFIG4      REG_BASE + 0x0D
+
+// Page 3 write only registers.
+#define TEST         REG_BASE + 0x07
+#define HLTCLK       REG_BASE + 0x09
+#define FMWP         REG_BASE + 0x0C
+
+
+// Bits del byte de status del frame recibido
+#define RXSOK      0x01    /* Received a good packet */
+#define RXSCRC     0x02    /* CRC error */
+#define RXSFAE     0x04    /* frame alignment error */
+#define RXSFO      0x08    /* FIFO overrun */
+#define RXSMPA     0x10    /* missed pkt */        
+#define RXSPHY     0x20    /* physical/multicast address */
+#define RXSDIS     0x40    /* receiver disable. set in monitor mode */
+#define RXSDEF     0x80    /* deferring */
+
+#endif
diff --git a/src/eth.c b/src/eth.c
new file mode 100644 (file)
index 0000000..6b9e162
--- /dev/null
+++ b/src/eth.c
@@ -0,0 +1,54 @@
+// vim: set et sw=4 sts=4 :    
+
+#include "netdev.h"
+#include "eth.h"
+
+/** tipos de paquetes transportados soportados */
+enum { IP = 0x0800, ARP = 0x0806 };
+
+byte eth_addr_local[ETH_ADDR_SIZE];
+
+byte eth_addr_remote[ETH_ADDR_SIZE];
+
+eth_proto_t eth_proto;
+
+bool eth_read_frame_header()
+{
+    /* variable para iterar */
+    byte i;
+    /* descarto MAC de destino, acepto broadcasts */
+    for (i = 0; i < ETH_ADDR_SIZE; ++i)
+        netdev_recv_byte();
+    /* obtenemos MAC de origen */
+    for (i = 0; i < ETH_ADDR_SIZE; ++i)
+        eth_addr_remote[i] = netdev_recv_byte();
+    /* obtenemos tipo de protocolo transportado por el frame, (sólo
+     * aceptamos IP y ARP) */
+    switch (netdev_recv_word())
+    {
+        case IP:
+            eth_proto = ETH_IP;
+            break;
+        case ARP:
+            eth_proto = ETH_ARP;
+            break;
+        default:
+            return false; /* drop */
+    }
+    return true;
+}
+
+void eth_write_frame_header()
+{
+    /* variable para iterar */
+    byte i;
+    /* mandamos como MAC de destino la remota */
+    for (i = 0; i < ETH_ADDR_SIZE; ++i)
+        netdev_send_byte(eth_addr_remote[i]);
+    /* y como fuente la nuestra */
+    for (i = 0; i < ETH_ADDR_SIZE; ++i)
+        netdev_send_byte(eth_addr_local[i]);
+    /* escribimos el tipo de paquete que transporta el frame */
+    netdev_send_word((eth_proto == ETH_IP) ? IP : ARP);
+}
+
similarity index 79%
rename from src/c/eth.h
rename to src/eth.h
index 54b1f53fb69805799512946b167a82d23f15e826..9a640de86b572d97aeee6b4907f665c957dbc8de 100644 (file)
+++ b/src/eth.h
@@ -1,8 +1,9 @@
+// vim: set et sw=4 sts=4 :    
+
 #ifndef _ETH_H_
 #define _ETH_H_
 
 #include "types.h"
-#include "net.h"
 
 /** @file
  * Estructura de un frame ethernet.
  */
 
 /** Tamaño de dirección MAC (en bytes) */
-#define MAC_ADDR_SIZE 6
+#define ETH_ADDR_SIZE 6
+
+/** Tipos de frame ethernet */
+typedef enum { ETH_IP, ETH_ARP } eth_proto_t;
 
 /** Dirección MAC nuestra */
-extern byte mac_addr_local[ETH_MAC_SIZE];
+extern byte eth_addr_local[ETH_ADDR_SIZE];
 
 /** Dirección MAC de destino */
-extern byte mac_addr_remote[ETH_MAC_SIZE];
+extern byte eth_addr_remote[ETH_ADDR_SIZE];
 
-/** Indica si el frame transporta ARP (si no transporta IP) */
-extern bool eth_frame_arp; /* FIXME: debería ser un bit manejado con ASM supongo */
+/** Indica que protocolo está transportando el frame */
+extern eth_proto_t eth_proto;
 
 /**
  * Lee la cabecera del frame ethernet.
diff --git a/src/etherled.Uv2 b/src/etherled.Uv2
new file mode 100644 (file)
index 0000000..f9bea75
--- /dev/null
@@ -0,0 +1,135 @@
+### uVision2 Project, (C) Keil Software\r
+### Do not modify !\r
+\r
+Target (etherled), 0x0000 // Tools: 'MCS-51'\r
+\r
+Group (net)\r
+Group (common)\r
+\r
+File 1,5,<.\netdev.h><netdev.h> 0x0 \r
+File 1,5,<.\dp8390.h><dp8390.h> 0x0 \r
+File 1,1,<.\dp8390.c><dp8390.c> 0x0 \r
+File 1,5,<.\eth.h><eth.h> 0x0 \r
+File 1,1,<.\eth.c><eth.c> 0x0 \r
+File 1,5,<.\ip.h><ip.h> 0x0 \r
+File 1,1,<.\ip.c><ip.c> 0x0 \r
+File 1,5,<.\udp.h><udp.h> 0x0 \r
+File 1,1,<.\udp.c><udp.c> 0x0 \r
+File 2,1,<.\main.c><main.c> 0x0 \r
+File 2,5,<.\reg51.h><reg51.h> 0x0 \r
+File 2,2,<.\startup.a51><startup.a51> 0x0 \r
+File 2,5,<.\types.h><types.h> 0x0 \r
+\r
+\r
+Options 1,0,0  // Target 'etherled'\r
+ Device (AT89S8252)\r
+ Vendor (Atmel)\r
+ Cpu (IRAM(0-0xFF) IROM(0-0x1FFF) CLOCK(24000000) MODA2)\r
+ FlashUt ()\r
+ StupF ("LIB\STARTUP.A51" ("Standard 8051 Startup Code"))\r
+ FlashDR ()\r
+ DevID ()\r
+ Rgf (REG8252.H)\r
+ Mem ()\r
+ C ()\r
+ A ()\r
+ RL ()\r
+ OH ()\r
+ DBC_IFX ()\r
+ DBC_CMS ()\r
+ DBC_AMS ()\r
+ DBC_LMS ()\r
+ UseEnv=0\r
+ EnvBin ()\r
+ EnvInc ()\r
+ EnvLib ()\r
+ EnvReg (ÿAtmel\)\r
+ OrgReg (ÿAtmel\)\r
+ TgStat=25\r
+ OutDir (.\)\r
+ OutName (etherled)\r
+ GenApp=1\r
+ GenLib=0\r
+ GenHex=1\r
+ Debug=1\r
+ Browse=1\r
+ LstDir (.\)\r
+ HexSel=0\r
+ MG32K=0\r
+ TGMORE=0\r
+ RunUsr 0 0 <>\r
+ RunUsr 1 0 <>\r
+ BrunUsr 0 0 <>\r
+ BrunUsr 1 0 <>\r
+ SVCSID <>\r
+ MODEL5=0\r
+ RTOS5=0\r
+ ROMSZ5=2\r
+ DHOLD5=0\r
+ XHOLD5=0\r
+ T51FL=208\r
+ XT51FL=0\r
+ CBANKS5=0\r
+ XBANKS5=0\r
+ RCB51 { 0,0,0,0,0,0,0,1,0 }\r
+ RXB51 { 0,0,0,0,0,0,0,0,0 }\r
+ OCM51 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }\r
+ OCR51 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }\r
+ IRO51 { 1,0,0,0,0,0,32,0,0 }\r
+ IRA51 { 0,0,0,0,0,0,1,0,0 }\r
+ XRA51 { 0,0,0,0,0,0,0,0,0 }\r
+ XRA512 { 0,0,0,0,0,0,0,0,0 }\r
+ IROM512 { 0,0,0,0,0,0,0,0,0 }\r
+ C51FL=21630224\r
+ C51VA=0\r
+ C51MSC ()\r
+ C51DEF ()\r
+ C51UDF ()\r
+ INCC5 ()\r
+ AX51FL=4\r
+ AX51MSC ()\r
+ AX51SET ()\r
+ AX51RST ()\r
+ INCA5 ()\r
+ PropFld { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }\r
+ IncBld=1\r
+ AlwaysBuild=0\r
+ GenAsm=0\r
+ AsmAsm=0\r
+ PublicsOnly=0\r
+ StopCode=3\r
+ CustArgs ()\r
+ LibMods ()\r
+ BankNo=65535\r
+ LX51FL=292\r
+ LX51OVL ()\r
+ LX51MSC ()\r
+ LX51DWN ()\r
+ LX51LFI ()\r
+ LX51ASN ()\r
+ LX51RES ()\r
+ LX51CCL ()\r
+ LX51UCL ()\r
+ LX51CSC ()\r
+ LX51UCS ()\r
+ LX51COB ()\r
+ LX51XDB ()\r
+ LX51PDB ()\r
+ LX51BIB ()\r
+ LX51DAB ()\r
+ LX51IDB ()\r
+ LX51PRC ()\r
+ LX51STK ()\r
+ LX51COS ()\r
+ LX51XDS ()\r
+ LX51BIS ()\r
+ LX51DAS ()\r
+ LX51IDS ()\r
+  OPTDL (S8051.DLL)()(DP51.DLL)(-p8252)(S8051.DLL)()(TP51.DLL)(-p8252)\r
+  OPTDBG 48125,0,()()()()()()()()()() ()()()()\r
+ FLASH1 { 0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0 }\r
+ FLASH2 ()\r
+ FLASH3 ()\r
+ FLASH4 ()\r
+EndOpt\r
+\r
diff --git a/src/ip.c b/src/ip.c
new file mode 100644 (file)
index 0000000..0b4b2e2
--- /dev/null
+++ b/src/ip.c
@@ -0,0 +1,163 @@
+// vim: set et sw=4 sts=4 :    
+
+#include "netdev.h"
+#include "ip.h"
+
+/** protocolos soportados */
+enum { ICMP = 0x01, UDP = 0x11 };
+
+byte ip_addr_local[IP_ADDR_SIZE];
+
+byte ip_addr_remote[IP_ADDR_SIZE];
+
+byte ip_packet_len;
+
+ip_proto_t ip_proto;
+
+/* para calcular checksum */
+static uint16 checksum;
+
+/* agrega un word al checksum calculado */
+static void sum(uint16 w)
+{
+    checksum += w;
+    if (checksum < w) /* corrección de carry (hubo OV) */
+        ++checksum;
+}
+
+bool ip_read_packet_header()
+{
+    /* variables utilitarias (iterar y/o buffer) */
+    byte h, l;
+    /* reseteamos checksum */
+    checksum = 0;
+    /* versión y tamaño de cabecera vienen en el 1er byte */
+    h = netdev_recv_byte();
+    /* sólo soportamos versión 4 */
+    if ((h >> 4) != 4)
+        return false; /* drop */
+    /* tamaño de cabecera */
+    if ((h & 0x0F) != 5) /* no aceptamos opciones raras =) */
+        return false; /* drop */
+    /* ignoramos el TOS y vamos calculando checksum */
+    sum(WORD(h, netdev_recv_byte()));
+    /* obtenemos tamaño del paquete */
+    if (h = netdev_recv_byte()) /* tiene más de 255 bytes (no lo soportamos) */
+        return false; /* drop */
+    ip_packet_len = netdev_recv_byte(); /* hasta 255 bytes tienen los nuestros */
+    /* vamos calculando checksum */
+    sum(WORD(h, ip_packet_len));
+    /* ignoramos identificación (2 bytes) y vamos calculando checksum */
+    sum(netdev_recv_word());
+    /* si tiene prendido el bit de MF (More Fragments, bit 5 del byte, bit 2
+     * de los flags de la cabecera) o si tiene un offset de fragmento (bits
+     * del 4 al 0 y todos los bits del byte siguiente), dropeamos (no
+     * soportamos fragmentación) */
+    h = netdev_recv_byte();
+    l = netdev_recv_byte();
+    if ((h & 0x3F) || l)
+        return false; /* drop */
+    /* seguimos calculando checksum */
+    sum(WORD(h, l));
+    /* no le damos bola al TTL (no le vamos a hacer lío si ya llegó hasta
+     * acá el pobre =) */
+    h = netdev_recv_byte();
+    /* protocolo (sólo soportamos UDP e ICMP) */
+    l = netdev_recv_byte();
+    switch (l)
+    {
+        case ICMP:
+            ip_proto = IP_ICMP;
+            break;
+        case UDP:
+            ip_proto = IP_UDP;
+            break;
+        default:
+            return false; /* drop */
+    }
+    /* sigo calculando checksum */
+    sum(WORD(h, l));
+    /* obtenemos checksum y seguimos el cálculo */
+    sum(netdev_recv_word());
+    /* obtenemos IP de origen (mientras seguimos calculando el checksum) */
+    for (l = 0; l < IP_ADDR_SIZE; ++l)
+    {
+        ip_addr_remote[l] = netdev_recv_byte();
+        if (l % 2)
+            sum(WORD(h, ip_addr_remote[l]));
+        else
+            h = ip_addr_remote[l];
+    }
+    /* vemos si el paquete es para nosotros (ningún soportar broadcast =)
+     * (mientras seguimos calculando el checksum) */
+    // TODO si soportamos DHCP hay que aceptar broadcasts!
+    for (l = 0; l < IP_ADDR_SIZE; ++l)
+    {
+        if (ip_addr_local[l] != netdev_recv_byte()) 
+            return false; /* drop (no es para nosotros) */
+        if (l % 2)
+            sum(WORD(h, ip_addr_local[l]));
+        else
+            h = ip_addr_local[l];
+    }
+    /* verificamos checksum */
+    if ((uint16)~checksum)
+        return false; /* checksum malo, drop */
+    return true;
+}
+
+void ip_write_packet_header()
+{
+    /* variables utilitarias (iterar y/o buffer) */
+    byte h, l;
+    /* identificador del paquete IP (incrementa con cada paquete) */
+    static uint16 id;
+    /* reseteamos checksum */
+    checksum = 0;
+    /* versión (4) y tamaño de cabecera (5 words de 4 bytes = 20 bytes) */
+    netdev_send_byte(h = 0x45);
+    /* TOS (0xc0 = Internetwork Control, 0x00 = normal) */
+    l = (ip_proto == IP_ICMP) ? 0xc0 : 0x00;
+    netdev_send_byte(l);
+    sum(WORD(h, l)); /* actualizamos checksum */
+    /* escribimos tamaño del paquete */
+    netdev_send_byte(h = 0x00); /* nunca vamos a mandar algo de más de 255 bytes */
+    netdev_send_byte(ip_packet_len);
+    sum(WORD(h, ip_packet_len)); /* actualizamos checksum */
+    /* identificación (sirve para reensamblar paquetes) */
+    netdev_send_word(id);
+    sum(id); /* actualizamos checksum */
+    /* pedimos que no se fragmente */
+    netdev_send_byte(h = 0x40); /* Don't Fragment (DF) = 1 */
+    netdev_send_byte(l = 0x00); /* offset de fragmento = 0 */
+    sum(WORD(h, l)); /* actualizamos checksum */
+    /* TTL de 64 saltos porque está de moda */
+    netdev_send_byte(h = 0x40);
+    /* protocolo (sólo soportamos UDP e ICMP) */
+    l = (ip_proto == IP_ICMP) ? ICMP : UDP;
+    netdev_send_byte(l);
+    sum(WORD(h, l)); /* actualizamos checksum */
+    /* checksum: antes de poder escribir el checksum hay que terminar de
+     * calcularlo según las direcciones IP de origen y destino, así que eso
+     * hacemos */
+    for (l = 0; l < IP_ADDR_SIZE; ++l) /* origen = local */
+        if (l % 2)
+            sum(WORD(h, ip_addr_local[l]));
+        else
+            h = ip_addr_local[l];
+    for (l = 0; l < IP_ADDR_SIZE; ++l) /* destino = remota */
+        if (l % 2)
+            sum(WORD(h, ip_addr_remote[l]));
+        else
+            h = ip_addr_remote[l];
+    /* ahora sí grabamos el checksum */
+    netdev_send_word(~checksum);
+    /* ahora sí, continuamos poniendo las direcciones */
+    /* ponemos como dirección IP de origen la nuestra */
+    for (l = 0; l < IP_ADDR_SIZE; ++l)
+        netdev_send_byte(ip_addr_local[l]);
+    /* IP de destino, la remota */
+    for (l = 0; l < IP_ADDR_SIZE; ++l)
+        netdev_send_byte(ip_addr_remote[l]);
+}
+
similarity index 94%
rename from src/c/ip.h
rename to src/ip.h
index ec3a8927fc53299e25a790d6e693fa5fe1906dd4..0b3fff19b5ff8a58cf64d5e91092712431e267c0 100644 (file)
+++ b/src/ip.h
@@ -1,8 +1,9 @@
+// vim: set et sw=4 sts=4 :    
+
 #ifndef _IP_H_
 #define _IP_H_
 
 #include "types.h"
-#include "net.h"
 
 /** @file
  * Paquete IP.
@@ -34,6 +35,9 @@
 /** Tamaño de dirección IP (en bytes) */
 #define IP_ADDR_SIZE 4
 
+/** Tipos de paquete IP */
+typedef enum { IP_UDP, IP_ICMP } ip_proto_t;
+
 /** Dirección IP nuestra */
 extern byte ip_addr_local[IP_ADDR_SIZE];
 
@@ -44,7 +48,7 @@ extern byte ip_addr_remote[IP_ADDR_SIZE];
 extern byte ip_packet_len;
 
 /** Indica si el paquete es ICMP (si no es UDP) */
-bool ip_proto_icmp;
+extern ip_proto_t ip_proto;
 
 /** Lee la cabecera del paquete IP.
  *
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..7cd2716
--- /dev/null
@@ -0,0 +1,112 @@
+// vim: set et sw=4 sts=4 :    
+
+#include "netdev.h"
+#include "eth.h"
+#include "ip.h"
+#include "udp.h"
+
+#ifdef SDCC
+static xdata at 0x0080 byte leds0;
+static xdata at 0x00c0 byte leds1;
+#else
+static byte xdata leds0 _at_ 0x0080;
+static byte xdata leds1 _at_ 0x00c0;
+#endif
+
+#define leds(word)              \
+    do                          \
+    {                           \
+        leds0 = ~LOW(word);     \
+        leds1 = ~HIGH(word);    \
+    }                           \
+    while (0)
+        
+
+void sleep(unsigned char times)
+{
+    unsigned int i;
+    unsigned char j;
+    for (i = 0; i < 0xffff; ++i)
+        for (j = 0; j < times; ++j);
+}
+
+void main(void)
+{
+    // Apagamos todos los leds
+    leds(0x0000);
+
+    // Inicializamos dispositivo de red
+    if (!netdev_init())
+    {
+        leds(0xffff);
+        while(1); // Si falla init nos quedamos bobos
+    }
+
+    // Inicializo IP
+    ip_addr_local[0] = 10;
+    ip_addr_local[1] = 10;
+    ip_addr_local[2] = 10;
+    ip_addr_local[3] = 100;
+
+    // Inicializo puerto UDP
+    udp_port_local = 9000;
+
+    while (1) // Forever
+    {
+        uint16 len = netdev_recv_start();
+        if (!len) // no recibimos nada
+        {
+            netdev_recv_end();
+            continue; // vamos de nuevo!
+        }
+
+        // Parseamos cabecera ethernet
+        if (!eth_read_frame_header()) // No es un buen header
+        {
+        // Tenemos algo!
+            netdev_recv_end(); // Tiramos el paquete
+            continue; // Vamos de nuevo!
+        }
+
+        // Vemos que protocolo transporta
+        switch (eth_proto)
+        {
+            case ETH_ARP: // FIXME, implementar ARP!
+                netdev_recv_end(); // Tiramos el paquete
+                continue; // Vamos de nuevo!
+
+            case ETH_IP:
+                // Parseamos cabecera IP
+                if (!ip_read_packet_header()) // No es un buen header
+                {
+                    netdev_recv_end(); // Tiramos el paquete
+                    continue; // Vamos de nuevo!
+                }
+
+                // Vemos que protocolo transporta
+                switch (ip_proto)
+                {
+                    case IP_ICMP: // FIXME, implementar ICMP!
+                        netdev_recv_end(); // Tiramos el paquete
+                        continue; // Vamos de nuevo!
+
+                    case IP_UDP:
+                        // Parseamos cabecera UDP
+                        if (!udp_read_dgram_header()) // No es un buen header
+                        {
+                            netdev_recv_end(); // Tiramos el paquete
+                            continue; // Vamos de nuevo!
+                        }
+
+                        // TODO
+                        // Nuestro protocolo, por ahora un simple echo!
+                        for (len = 8; len < udp_dgram_len; len += 2) // 8 por la cabecera UDP
+                        {
+                            leds(netdev_recv_word());
+                            sleep(5);
+                        }
+                }
+        }
+    }
+}
+
diff --git a/src/netdev.h b/src/netdev.h
new file mode 100644 (file)
index 0000000..635432b
--- /dev/null
@@ -0,0 +1,55 @@
+// vim: set et sw=4 sts=4 :    
+
+#ifndef _NETDEV_H_
+#define _NETDEV_H_
+
+#include "types.h"
+
+/** Inicializa dispositivo de red
+ * @return true si se inicializó correctamente, false si no
+ */
+bool netdev_init();
+
+/** Comienza el envío de un nuevo frame
+ * @param len Tamaño del frame a enviar
+ */
+void netdev_send_start();
+
+/** Escribe un byte al buffer de la placa de red para ser enviado
+ * @precond netdev_send_start() debe haber sido ejecutada
+ * @param b Byte a enviar
+ */
+void netdev_send_byte(byte b);
+
+/** Escribe un word al buffer de la placa de red para ser enviado
+ * @precond netdev_send_start() debe haber sido ejecutada
+ * @param w Word a enviar
+ */
+void netdev_send_word(uint16 w);
+
+/** Finaliza el envío del frame
+ * @precond netdev_send_start() debe haber sido ejecutada
+ */
+void netdev_send_end();
+
+/** Comienza la lectura de un nuevo frame
+ * @return Cantidad de bytes del frame leído
+ */
+byte netdev_recv_start();
+
+/** Lee un byte del buffer de la placa de red
+ * @precond netdev_recv_start() debe haber sido ejecutada
+ */
+byte netdev_recv_byte();
+
+/** Lee un word del buffer de la placa de red
+ * @precond netdev_recv_start() debe haber sido ejecutada
+ */
+uint16 netdev_recv_word();
+
+/** Finaliza la lectura del frame
+ * @precond netdev_recv_start() debe haber sido ejecutada
+ */
+void netdev_recv_end();
+
+#endif // _NETDEV_H_
diff --git a/src/reg51.h b/src/reg51.h
new file mode 100644 (file)
index 0000000..7b95f31
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _REG51_H_
+#define _REG51_H_
+
+#ifdef SDCC
+#      include "reg51sdcc.h"
+#else
+#      include "reg51keil.h"
+#endif
+
+#endif /* _REG51_H_ */
diff --git a/src/startup.a51 b/src/startup.a51
new file mode 100644 (file)
index 0000000..d9a8780
--- /dev/null
@@ -0,0 +1,157 @@
+$NOMOD51
+;------------------------------------------------------------------------------
+;  This file is part of the C51 Compiler package
+;  Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc.
+;------------------------------------------------------------------------------
+;  STARTUP.A51:  This code is executed after processor reset.
+;
+;  To translate this file use A51 with the following invocation:
+;
+;     A51 STARTUP.A51
+;
+;  To link the modified STARTUP.OBJ file to your application use the following
+;  BL51 invocation:
+;
+;     BL51 <your object file list>, STARTUP.OBJ <controls>
+;
+;------------------------------------------------------------------------------
+;
+;  User-defined Power-On Initialization of Memory
+;
+;  With the following EQU statements the initialization of memory
+;  at processor reset can be defined:
+;
+;               ; the absolute start-address of IDATA memory is always 0
+IDATALEN        EQU     80H     ; the length of IDATA memory in bytes.
+;
+XDATASTART      EQU     0H      ; the absolute start-address of XDATA memory
+XDATALEN        EQU     400H    ; the length of XDATA memory in bytes.
+;
+PDATASTART      EQU     0H      ; the absolute start-address of PDATA memory
+PDATALEN        EQU     0H      ; the length of PDATA memory in bytes.
+;
+;  Notes:  The IDATA space overlaps physically the DATA and BIT areas of the
+;          8051 CPU. At minimum the memory space occupied from the C51 
+;          run-time routines must be set to zero.
+;------------------------------------------------------------------------------
+;
+;  Reentrant Stack Initilization
+;
+;  The following EQU statements define the stack pointer for reentrant
+;  functions and initialized it:
+;
+;  Stack Space for reentrant functions in the SMALL model.
+IBPSTACK        EQU     0       ; set to 1 if small reentrant is used.
+IBPSTACKTOP     EQU     0FFH+1  ; set top of stack to highest location+1.
+;
+;  Stack Space for reentrant functions in the LARGE model.      
+XBPSTACK        EQU     0       ; set to 1 if large reentrant is used.
+XBPSTACKTOP     EQU     0FFFFH+1; set top of stack to highest location+1.
+;
+;  Stack Space for reentrant functions in the COMPACT model.    
+PBPSTACK        EQU     0       ; set to 1 if compact reentrant is used.
+PBPSTACKTOP     EQU     0FFFFH+1; set top of stack to highest location+1.
+;
+;------------------------------------------------------------------------------
+;
+;  Page Definition for Using the Compact Model with 64 KByte xdata RAM
+;
+;  The following EQU statements define the xdata page used for pdata
+;  variables. The EQU PPAGE must conform with the PPAGE control used
+;  in the linker invocation.
+;
+PPAGEENABLE     EQU     0       ; set to 1 if pdata object are used.
+;
+PPAGE           EQU     0       ; define PPAGE number.
+;
+PPAGE_SFR       DATA    0A0H    ; SFR that supplies uppermost address byte
+;               (most 8051 variants use P2 as uppermost address byte)
+;
+;------------------------------------------------------------------------------
+
+; Standard SFR Symbols 
+ACC     DATA    0E0H
+B       DATA    0F0H
+SP      DATA    81H
+DPL     DATA    82H
+DPH     DATA    83H
+
+                NAME    ?C_STARTUP
+
+
+?C_C51STARTUP   SEGMENT   CODE
+?STACK          SEGMENT   IDATA
+
+                RSEG    ?STACK
+                DS      1
+
+                EXTRN CODE (?C_START)
+                PUBLIC  ?C_STARTUP
+
+                CSEG    AT      0
+?C_STARTUP:     LJMP    STARTUP1
+
+                RSEG    ?C_C51STARTUP
+
+STARTUP1:
+
+IF IDATALEN <> 0
+                MOV     R0,#IDATALEN - 1
+                CLR     A
+IDATALOOP:      MOV     @R0,A
+                DJNZ    R0,IDATALOOP
+ENDIF
+
+IF XDATALEN <> 0
+                MOV     DPTR,#XDATASTART
+                MOV     R7,#LOW (XDATALEN)
+  IF (LOW (XDATALEN)) <> 0
+                MOV     R6,#(HIGH (XDATALEN)) +1
+  ELSE
+                MOV     R6,#HIGH (XDATALEN)
+  ENDIF
+                CLR     A
+XDATALOOP:      MOVX    @DPTR,A
+                INC     DPTR
+                DJNZ    R7,XDATALOOP
+                DJNZ    R6,XDATALOOP
+ENDIF
+
+IF PPAGEENABLE <> 0
+                MOV     PPAGE_SFR,#PPAGE
+ENDIF
+
+IF PDATALEN <> 0
+                MOV     R0,#LOW (PDATASTART)
+                MOV     R7,#LOW (PDATALEN)
+                CLR     A
+PDATALOOP:      MOVX    @R0,A
+                INC     R0
+                DJNZ    R7,PDATALOOP
+ENDIF
+
+IF IBPSTACK <> 0
+EXTRN DATA (?C_IBP)
+
+                MOV     ?C_IBP,#LOW IBPSTACKTOP
+ENDIF
+
+IF XBPSTACK <> 0
+EXTRN DATA (?C_XBP)
+
+                MOV     ?C_XBP,#HIGH XBPSTACKTOP
+                MOV     ?C_XBP+1,#LOW XBPSTACKTOP
+ENDIF
+
+IF PBPSTACK <> 0
+EXTRN DATA (?C_PBP)
+                MOV     ?C_PBP,#LOW PBPSTACKTOP
+ENDIF
+
+                MOV     SP,#?STACK-1
+; This code is required if you use L51_BANK.A51 with Banking Mode 4
+; EXTRN CODE (?B_SWITCH0)
+;               CALL    ?B_SWITCH0      ; init bank mechanism to code bank 0
+                LJMP    ?C_START
+
+                END
similarity index 57%
rename from src/c/types.h
rename to src/types.h
index 52b07d14e6b00a7ccd1bdfd954348804eee93695..3bd0dc62f3c971cd33e4f0974086edc61b016e8a 100644 (file)
@@ -1,38 +1,21 @@
 #ifndef _TYPES_H_
 #define _TYPES_H_
 
-/** valores posibles de un booleano */
-enum { false = 0, true = 1 };
-
-/** convierte 2 bytes (high, low) en un word */
-#define WORD(high, low) ((high << 8) + low)
-
-/** convierte un word en 2 bytes */
-#define UNPACK(word, high, low) (high = (word >> 8), low = word)
-
-/** obtiene parte alta de un word */
-#define HIGH(word) (word >> 8)
-
-/** obtiene parte baja de un word */
-#define LOW(word) (word)
-
-#if 1 /* i386 */
+#if 0 /* i386 */
+#include <stdint.h>
 
 /** booleano */
 typedef unsigned char bool;
 
 /** entero sin signo de 8 bits */
-typedef unsigned char byte;
+typedef uint8_t byte;
 
 /** entero sin signo de 16 bits */
-typedef unsigned short uint16;
+typedef uint16_t uint16;
 
 #endif
 
-#if 0 /* 8051 */
-
-/** booleano */
-typedef unsigned char bool;
+#if 1 /* 8051 */
 
 /** entero sin signo de 8 bits */
 typedef unsigned char byte;
@@ -40,6 +23,30 @@ typedef unsigned char byte;
 /** entero sin signo de 16 bits */
 typedef unsigned int uint16;
 
+#ifdef SDCC
+/** booleano */
+typedef byte bool;
+#else
+/** booleano */
+typedef bit bool;
+#endif
+
 #endif
 
+/** valores posibles de un booleano */
+enum { false = 0, true = 1 };
+
+/** convierte 2 bytes (high, low) en un word */
+#define WORD(high, low) ((uint16)((uint16)(high << 8) + (uint16)low))
+
+/** convierte un word en 2 bytes */
+#define UNPACK(word, high, low) (high = (byte)(word >> 8), \
+                                 low = (byte)word & 0xFF)
+
+/** obtiene parte alta de un word */
+#define HIGH(word) ((byte)(word >> 8))
+
+/** obtiene parte baja de un word */
+#define LOW(word) ((byte)(word & 0xFF))
+
 #endif /* _TYPES_H_ */
diff --git a/src/udp.c b/src/udp.c
new file mode 100644 (file)
index 0000000..9da1b25
--- /dev/null
+++ b/src/udp.c
@@ -0,0 +1,118 @@
+// vim: set et sw=4 sts=4 :    
+
+#include "netdev.h"
+#include "ip.h"
+#include "udp.h"
+
+uint16 udp_port_local;
+
+uint16 udp_port_remote;
+
+byte udp_dgram_len;
+
+/* para calcular checksum */
+static uint16 checksum;
+
+/* agrega un word al checksum calculado */
+static void sum(uint16 w)
+{
+    checksum += w;
+    if (checksum < w) /* corrección de carry (hubo OV) */
+        ++checksum;
+}
+
+bool udp_read_dgram_header()
+{
+    uint16 p;
+    /* reseteamos checksum */
+    checksum = 0;
+    /* el UDP tiene un checksum que incluye parte de la cabecera IP */
+    /* ip de origen */
+    sum(WORD(ip_addr_remote[0], ip_addr_remote[1]));
+    sum(WORD(ip_addr_remote[2], ip_addr_remote[3]));
+    /* ip de destino */
+    sum(WORD(ip_addr_local[0], ip_addr_local[1]));
+    sum(WORD(ip_addr_local[2], ip_addr_local[3]));
+    /* protocolo expresado en 16 bits (0x11 es UDP) */
+    sum(0x0011);
+    /* tamaño del paquete UDP (sin las cabeceras que son 20 bytes) */
+    sum(ip_packet_len - 20);
+    /* de ahora en más todos los datos del checksum corresponden a UDP */
+    /* puerto origen (remoto) */
+    udp_port_remote = netdev_recv_word();
+    /* agregamos puerto de origen al checksum */
+    sum(udp_port_remote);
+    /* sólo aceptamos datagramas a nuestro puerto */
+    p = netdev_recv_word();
+    if (p != udp_port_local)
+        return false; /* drop */
+    /* agregamos puerto de destino al checksum */
+    sum(udp_port_local);
+    /* tamaño del datagrama */
+    if (netdev_recv_byte()) /* no soportamos más de 255 bytes */
+        return false; /* drop */
+    udp_dgram_len = netdev_recv_byte();
+    /* agregamos tamaño al checksum */
+    sum(udp_dgram_len);
+    /* agregamos checksum al checksum */
+    sum(netdev_recv_word());
+    /* falta agregar el cuerpo del mensaje para verificar la suma
+     * esto debe hacerlo el protocolo que sigue para poder seguir obteniendo
+     * los datos de la placa de red byte a byte */
+    return true;
+}
+
+uint16 udp_read_word()
+{
+    uint16 w = netdev_recv_word();
+    sum(w);
+    return w;
+}
+
+bool udp_checksum_ok()
+{
+    return (uint16)~checksum;
+}
+
+void udp_write_dgram_header()
+{
+    /* reseteamos checksum */
+    checksum = 0;
+    /* el UDP tiene un checksum que incluye parte de la cabecera IP */
+    /* ip de origen */
+    sum(WORD(ip_addr_remote[0], ip_addr_remote[1]));
+    sum(WORD(ip_addr_remote[2], ip_addr_remote[3]));
+    /* ip de destino */
+    sum(WORD(ip_addr_local[0], ip_addr_local[1]));
+    sum(WORD(ip_addr_local[2], ip_addr_local[3]));
+    /* protocolo expresado en 16 bits (0x11 es UDP) */
+    sum(0x0011);
+    /* tamaño del paquete UDP (IP sin las cabeceras, que son 20 bytes) */
+    sum(ip_packet_len - 20); // FIXME
+    /* puerto origen */
+    netdev_send_word(udp_port_local);
+    sum(udp_port_local);
+    /* puerto destino */
+    netdev_send_word(udp_port_remote);
+    sum(udp_port_remote);
+    /* tamaño del datagrama */
+    netdev_send_byte(0x00); /* parte alta en 0 porque no soportamos más de 255 */
+    netdev_send_byte(udp_dgram_len);
+    sum(WORD(0x00, udp_dgram_len));
+    /* indicamos que no se usa checksum */
+    netdev_send_word(0x0000);
+    sum(0x0000);
+}
+
+void udp_write_word(uint16 w)
+{
+    sum(w);
+    netdev_send_word(w);
+}
+
+void udp_write_checksum()
+{
+    // XXX TODO FIXME
+    return;
+}
+
similarity index 80%
rename from src/c/udp.h
rename to src/udp.h
index 9530a1303ef7487a6cc063190dc2f07861a96a87..e9092f73039282939dade71589c2ab1d7c8176d6 100644 (file)
+++ b/src/udp.h
@@ -1,8 +1,9 @@
+// vim: set et sw=4 sts=4 :    
+
 #ifndef _UDP_H_
 #define _UDP_H_
 
 #include "types.h"
-#include "net.h"
 
 /** @file
  * Datagrama UDP.
@@ -27,7 +28,8 @@
  * es 8.
  *
  * El checksum se calcula utilizando algunos datos de la capa inferior e incluye
- * a los datos. Entonces es calculado sobre el siguiente paquete 'virtual':
+ * a los datos (completando con 0 al final si no es múltiplo de 2). Entonces es
+ * calculado sobre el siguiente paquete 'virtual':
  *
  * <pre>
  *  0      7 8     15 16    23 24    31  
@@ -45,7 +47,7 @@
  * |     Length      |    Checksum     | 
  * +--------+--------+--------+--------+ 
  * |                                     
- * |          data octets ...            
+ * |    data octets ... (padding)
  * +---------------- ...                 
  * </pre>
  */
@@ -67,6 +69,12 @@ extern byte udp_dgram_len;
  */
 bool udp_read_dgram_header();
 
+/** Recibe un word del payload UDP chequeando el checksum. */
+uint16 udp_read_word();
+
+/* Indica si el checksum calculado está ok */
+bool udp_checksum_ok();
+
 /** Escribe la cabecera del datagrama UDP.
  *
  * Pone como puerto destino a udp_port_remote, como origen udp_port_local y como
@@ -74,4 +82,10 @@ bool udp_read_dgram_header();
  */
 void udp_write_dgram_header();
 
+/** Escribe un word al payload UDP chequeando el checksum. */
+void udp_write_word(uint16 w);
+
+/* Escribe el checksum calculado al frame a enviar */
+void udp_write_checksum();
+
 #endif /* _UDP_H_ */