'dibujando', la red se comporta de manera rara (no funciona bien).
Paquete ELP
-----------
-
+0 1 N
+----------------+--------------------------------+
| CABECERA | DATOS (opcional) |
+----------------+--------------------------------+
-/---- 1 byte ----/---------- 0-64 bytes ----------/
+/---- 1 byte ----/----------- Variable -----------/
CABECERA
--------
La cabecera está compuesta por los siguientes campos:
-+-----+--------------------+---------------+
-| GS | VAR | ID |
-+-----+--------------------+---------------+
-/- 1 -/------ 4 bits ------/--- 3 bits ----/
+ 7 6 5 4 3 2 1 0
++-----+-----------------------+-----------------+
+| GS | VAR | ID |
++-----+-----------------------+-----------------+
+/- 1 -/------- 4 bits --------/---- 3 bits -----/
GS:
Este bit indica si la operación es GET (0) o SET (1).
| | | contenido de la matriz organizado
| | | como se indica en la sección Matriz
----+-------------+------------------+------------------------------------------
- 2 | DRAW | Prendido/apagado | 1 byte con conteniendo 0xFF para prender
- | | del dibujado | o con 0x00 para apagar
+ 2 | PAUSE | Pausa el dibuja- | 1 byte contenido 0x00 para reanudar el
+ | | do de la matriz | dibujado, cualquier otro para pausarlo
+----+-------------+------------------+------------------------------------------
+ 3 | DELAY | Tiempo de retar- | 1 byte sin signo con la cantidad de 0.05
+ | | do del dibujado | ms a esperar entre refresco de columnas
----+-------------+------------------+------------------------------------------
El resto de las variables quedan para futuras extensiones.
SHELL=bash
# Archivos
-cmodules=main dp8390 eth ip udp
+cmodules=main dp8390 eth ip udp elp
amodules=leds
modules=$(cmodules) $(amodules)
udp.h: types.h
+elp.h: types.h
+
dp8390.asm: dp8390.c dp8390.h debug.h eth.h
dp8390.rel: dp8390.asm
udp.asm: udp.c udp.h ip.h netdev.h debug.h
udp.rel: udp.asm
-main.asm: main.c leds.h reg51.h netdev.h eth.h ip.h udp.h debug.h
+elp.asm: elp.c elp.h leds.h udp.h netdev.h debug.h
+elp.rel: elp.asm
+
+main.asm: main.c leds.h reg51.h netdev.h eth.h ip.h udp.h elp.h debug.h
main.rel: main.asm
leds.rel: leds.asm
--- /dev/null
+// vim: set et sw=4 sts=4 :
+
+#include "debug.h"
+#include "elp.h"
+#include "reg51.h"
+#include "leds.h"
+#include "netdev.h"
+#include "udp.h"
+
+struct elp_command_t elp_command;
+
+byte elp_read_process_command()
+{
+ byte i;
+ byte len = ELP_HEADER_SIZE;
+ netdev_read_start(ELP_HEADER_SIZE);
+ // Escribimos el bitfield a lo guapo como un byte.
+ *((byte*) &elp_command) = udp_read_byte();
+ netdev_read_end();
+
+ printb(*((byte*) &elp_command), 0x01);
+
+ // Si es un SET lo proceso
+ switch (elp_command.var)
+ {
+ case ELP_VAR_OFF:
+ // Si es GET, sólo calculamos tamaño de respuesta
+ if (!elp_command.set)
+ return 0; // En este caso no tiene sentido un GET
+ // Si es SET procesamos (apagamos las luces y nos vamos a dormir)
+ leds_write(0x0000); // Apago leds
+ EA = 0; // Ignoramos interrupciones (por si el micro no soporta PD)
+ PCON = 0x02; // Bit PD (Power Down) prendido
+ while (1); // Nos negamos a seguir trabajando ( " )
+ // FIXME: No es del todo elegante esto, porque nunca vamos a
+ // responder el paquete
+
+ case ELP_VAR_MATRIX:
+ // Si es GET, sólo calculamos tamaño de respuesta
+ if (!elp_command.set)
+ // Vamos a devolver la matriz (2 bytes por columna) y su tamaño
+ return len + sizeof(leds_matrix_len) + leds_matrix_len * 2;
+ // Si es SET procesamos
+ netdev_read_start(sizeof(leds_matrix_len)); // tamaño
+ i = udp_read_byte();
+ netdev_read_end();
+ // Verifico cantidad de columnas
+ if ((LEDS_MIN_COLS < i) || (i < LEDS_MAX_COLS))
+ return 0;
+ leds_matrix_len = i;
+ netdev_read_start(leds_matrix_len * 2); // matriz
+ for (i = 0; i < leds_matrix_len; ++i)
+ {
+ byte low = udp_read_byte();
+ leds_matrix[i] = WORD(udp_read_byte(), low);
+ }
+ netdev_read_end();
+ leds_delay_update(); // Seteamos un delay bueno
+ return len;
+
+ case ELP_VAR_PAUSE:
+ // Si es GET, sólo calculamos tamaño de respuesta
+ if (!elp_command.set)
+ return len + 1 /* booleano de 1 byte */;
+ // Si es SET procesamos
+ netdev_read_start(1); // booleano de 1 byte
+ //XXX if (udp_read_byte() == 0x00) // si viene 0 reanuda
+ //XXX TR2 = 1;
+ //XXX else
+ if (udp_read_byte() != 0x00)
+ {
+ TR2 = 0;
+ leds_write(0x0000); // Si pausa apaga leds
+ }
+ netdev_read_end();
+ return len;
+
+ case ELP_VAR_DELAY:
+ // Si es GET, sólo calculamos tamaño de respuesta
+ if (!elp_command.set)
+ return len + sizeof(leds_delay);
+ // Si es SET procesamos
+ netdev_read_start(sizeof(leds_delay));
+ leds_delay = udp_read_byte();
+ netdev_read_end();
+ return len;
+
+ default:
+ // Desconocido
+ return 0;
+ }
+}
+
+void elp_write_response()
+{
+ byte i;
+ // Escribimos cabecera
+ netdev_write_start(ELP_HEADER_SIZE);
+ // Escribimos el bitfield a lo guapo como un byte.
+ udp_write_byte(*((byte*) &elp_command));
+ netdev_write_end();
+ // Si era un SET acá termino nuestro trabajo, nunca tiene datos
+ if (elp_command.set)
+ return;
+ // Si era un GET escribimos lo que nos pidieron
+ switch (elp_command.var)
+ {
+ case ELP_VAR_MATRIX:
+ // Transferimos tamaño (1 byte) + matriz (2 bytes por columna)
+ netdev_write_start(sizeof(leds_matrix_len) + leds_matrix_len * 2);
+ udp_write_byte(leds_matrix_len);
+ for (i = 0; i < leds_matrix_len; ++i)
+ {
+ udp_write_byte(LOW(leds_matrix[i]));
+ udp_write_byte(HIGH(leds_matrix[i]));
+ }
+ netdev_write_end();
+ break;
+
+ case ELP_VAR_PAUSE:
+ netdev_write_start(1 /* booleano de 1 byte */);
+ udp_write_byte(!TR2);
+ netdev_write_end();
+ break;
+
+ case ELP_VAR_DELAY:
+ netdev_write_start(sizeof(leds_delay));
+ udp_write_byte(leds_delay);
+ netdev_write_end();
+ break;
+ }
+}
+
--- /dev/null
+// vim: set et sw=4 sts=4 :
+
+#ifndef _ELP_H_
+#define _ELP_H_
+
+#include "types.h"
+
+/** @file
+ * Protocolo de etherled (elp == Etherled Protocol).
+ *
+ * Ver archivo protocolo.txt en la documentación.
+ */
+
+/** Puerto UDP usado por el protocolo ELP */
+#define ELP_PORT 9876u
+
+/** Variables del comando */
+#define ELP_VAR_OFF 0
+#define ELP_VAR_MATRIX 1
+#define ELP_VAR_PAUSE 2
+#define ELP_VAR_DELAY 3
+
+/** Comando recibido/a enviar */
+extern struct elp_command_t
+{
+ byte id: 3; ///< Identificador del paquete
+ byte var: 4; ///< Variable a leer/escribir
+ byte set: 1; ///< SET (1) / GET (0)
+}
+elp_command;
+
+/** Tamaño de la cabecera ELP */
+#define ELP_HEADER_SIZE (sizeof(struct elp_command_t))
+
+/** Procesa un comando ELP.
+ * @precond Se ejecutó netdev_recv_start().
+ * @returns cantidad de bytes escritos, 0 indica error o comando no soportado.
+ */
+byte elp_read_process_command();
+
+/** Escribe la respuesta al comando.
+ * @precond Se ejecutó netdev_send_start().
+ */
+void elp_write_response();
+
+#endif /* _ELP_H_ */
; Constantes
; UN CICLO DE MAQUINA SON 1.6666 useg (clock 8MHz)
-INTERVAL = 33 ; 0.05ms (por el clock de 8MHz)
-LEDS_HIGH = 0x0080
-LEDS_LOW = 0x00c0
+INTERVAL = 65000 ; 0.05ms (por el clock de 8MHz)
+LEDS_LOW = 0x0080
+LEDS_HIGH = 0x00c0
DELAY_BASE = 28 ; 16 columnas anda bien con 28 - (len / 2) == 20
; Área de bancos de registros
mov r2, a ; tamaño en bytes de la matriz
; Cargo milisegundos
- acall _leds_delay_update
+ lcall _leds_delay_update
mov delay, _leds_delay
; copio imagen por default de la ROM a la RAM
_leds_test::
; escribo patrones en los leds
mov dptr, #0xffff
- acall _leds_write
- acall sleep
+ lcall _leds_write
+ lcall sleep
mov dptr, #0xaaaa
- acall _leds_write
- acall sleep
+ lcall _leds_write
+ lcall sleep
mov dptr, #0x5555
- acall _leds_write
- acall sleep
+ lcall _leds_write
+ lcall sleep
mov dptr, #0x0000
- acall _leds_write
- acall sleep
+ lcall _leds_write
+ lcall sleep
ret
mov dpl, a
mov a, #DELAY_BASE
subb a, dpl
- mov _leds_matrix_len, a
+ mov _leds_delay, a
ret
add a, r0 ; le sumo al puntero el offset actual segun la columna
mov r0, a
- ; imprimo en LEDS_LOW
+ ; imprimo en LEDS_HIGH
mov a, @r0 ; leo el contenido de la matriz
- mov dptr, #LEDS_LOW
+ mov dptr, #LEDS_HIGH
cpl a ; complemento para ver encendidos los "1"
movx @dptr, a
- ; imprimo en LEDS_HIGH
+ ; imprimo en LEDS_LOW
inc r0 ; busco proximo byte de la columna
mov a, @r0 ; leo el contenido de la matriz
- mov dptr, #LEDS_HIGH
+ mov dptr, #LEDS_LOW
cpl a ; complemento para ver encendidos los "1"
movx @dptr, a
;.db 32
DEFAULT_MATRIX:
- .dw 0b0000111111110000 ; columna 0
- .dw 0b0011111111111100 ; columna 1
- .dw 0b0111000000001110 ; columna 2
- .dw 0b0110000000000110 ; columna 3
- .dw 0b1100001100000011 ; columna 4
- .dw 0b1100011000110011 ; columna 5
- .dw 0b1100110000110011 ; columna 6
- .dw 0b1100110000000011 ; columna 7
- .dw 0b1100110000000011 ; columna 8
- .dw 0b1100110000110011 ; columna 9
- .dw 0b1100011000110011 ; columna 10
- .dw 0b1100001100000011 ; columna 11
- .dw 0b0110000000000110 ; columna 12
- .dw 0b0111000000001110 ; columna 13
- .dw 0b0011111111111100 ; columna 14
- .dw 0b0000111111110000 ; columna 15
-
- .dw 0b1111000000001111 ; columna 0
- .dw 0b1100000000000011 ; columna 1
- .dw 0b1000111111110001 ; columna 2
- .dw 0b1001111111111001 ; columna 3
- .dw 0b0011001111111100 ; columna 4
- .dw 0b0011100111001100 ; columna 5
- .dw 0b0011110011001100 ; columna 6
- .dw 0b0011110011111100 ; columna 7
- .dw 0b0011110011111100 ; columna 8
- .dw 0b0011110011001100 ; columna 9
- .dw 0b0011100111001100 ; columna 01
- .dw 0b0011001111111100 ; columna 00
- .dw 0b1001111111111001 ; columna 01
- .dw 0b1000111111110001 ; columna 03
- .dw 0b1100000000000011 ; columna 04
- .dw 0b1111000000001111 ; columna 05
+; .dw 0b0000111111110000 ; columna 0
+; .dw 0b0011111111111100 ; columna 1
+; .dw 0b0111000000001110 ; columna 2
+; .dw 0b0110000000000110 ; columna 3
+; .dw 0b1100001100000011 ; columna 4
+; .dw 0b1100011000110011 ; columna 5
+; .dw 0b1100110000110011 ; columna 6
+; .dw 0b1100110000000011 ; columna 7
+; .dw 0b1100110000000011 ; columna 8
+; .dw 0b1100110000110011 ; columna 9
+; .dw 0b1100011000110011 ; columna 10
+; .dw 0b1100001100000011 ; columna 11
+; .dw 0b0110000000000110 ; columna 12
+; .dw 0b0111000000001110 ; columna 13
+; .dw 0b0011111111111100 ; columna 14
+; .dw 0b0000111111110000 ; columna 15
+
+ .dw 0b0000011111100000
+ .dw 0b0001111111111000
+ .dw 0b0011100000011100
+ .dw 0b0111110000000110
+ .dw 0b0110111000000110
+ .dw 0b1100011100000011
+ .dw 0b1100001110000011
+ .dw 0b1111111111111111
+ .dw 0b1111111111111111
+ .dw 0b1100001110000011
+ .dw 0b1100011100000011
+ .dw 0b0110111000000110
+ .dw 0b0111110000000110
+ .dw 0b0011100000011100
+ .dw 0b0001111111111000
+ .dw 0b0000011111100000
+
+; .dw 0b1111000000001111 ; columna 0
+; .dw 0b1100000000000011 ; columna 1
+; .dw 0b1000111111110001 ; columna 2
+; .dw 0b1001111111111001 ; columna 3
+; .dw 0b0011001111111100 ; columna 4
+; .dw 0b0011100111001100 ; columna 5
+; .dw 0b0011110011001100 ; columna 6
+; .dw 0b0011110011111100 ; columna 7
+; .dw 0b0011110011111100 ; columna 8
+; .dw 0b0011110011001100 ; columna 9
+; .dw 0b0011100111001100 ; columna 01
+; .dw 0b0011001111111100 ; columna 00
+; .dw 0b1001111111111001 ; columna 01
+; .dw 0b1000111111110001 ; columna 03
+; .dw 0b1100000000000011 ; columna 04
+; .dw 0b1111000000001111 ; columna 05
; .dw 0b0000001111100000 ; columna 0
; .dw 0b0000111110000000 ; columna 1
#ifndef _LEDS_H_
#define _LEDS_H_
+/** Cantidad mínima de columnas (es más un límite estético que físico) */
+#define LEDS_MIN_COLS 8
+
/** Cantidad máxima de columnas */
#define LEDS_MAX_COLS 32
extern unsigned char leds_matrix_len;
/** Matriz de leds, cada elemento del array es una columna */
-extern unsigned int leds_matrix[LEDS_MAX_COLS];
+extern idata unsigned int leds_matrix[LEDS_MAX_COLS];
/** Retardo de refresco de la matriz (en múltiplos de 0.1ms) */
extern unsigned char leds_delay;
#include "eth.h"
#include "ip.h"
#include "udp.h"
+#include "elp.h"
void main(void)
{
// Comienza a 'dibujar'
EA = 1; // Habilita interrupciones globalmente
- TR2 = 1; // Pone a correr el 'dibujado'
+ //XXX TR2 = 1; // Pone a correr el 'dibujado'
// Inicializo IP
ip_addr_local[0] = 10;
ip_addr_local[3] = 100;
// Inicializo puerto UDP
- udp_port_local = 9876;
+ udp_port_local = ELP_PORT;
while (1) // Forever
{
- byte i; //XXX
- byte len;
-
- len = netdev_recv_start();
+ byte len = netdev_recv_start();
+ //printb(len, 0x10);
if (!len) // no recibimos nada (válido)
continue; // Probamos de nuevo
// Tenemos algo!
- //print(0x2);
// Parseamos cabecera ethernet
if (!eth_read_frame_header()) // No es un buen header
goto drop; // Tiramos el paquete
- //print(0x4);
// Vemos que protocolo transporta
switch (eth_proto)
goto drop; // Tiramos el paquete
case ETH_IP:
- //print(0x8);
// Parseamos cabecera IP
if (!ip_read_packet_header()) // No es un buen header
goto drop; // Tiramos el paquete
- //print(0x10);
// Vemos que protocolo transporta
switch (ip_proto)
goto drop; // Tiramos el paquete
case IP_UDP:
- //print(0x20);
// Parseamos cabecera UDP
if (!udp_read_dgram_header()) // No es un buen header
goto drop; // Tiramos el paquete
- //printb(udp_dgram_len, 0x40);
- // TODO
- // Nuestro protocolo, por ahora un simple echo!
- len = udp_dgram_len - UDP_HEADER_SIZE;
- netdev_read_start(len);
- leds_matrix_len = len;
- for (i = 0; i < len; ++i)
- leds_matrix[i] = udp_read_byte();
- netdev_read_end();
+ // Procesamos comando ELP y obtenemos tamaño de la
+ // respuesta
+ len = elp_read_process_command();
+ printb(len, 0x02);
+
+ // Si el tamaño es 0, hubo error o no está soportado
+ if (!len)
+ goto drop;
+ print(0x0004);
+
+ // FIXME por ahora no tenemos forma de 'abortar' el
+ // comando si el checksum es incorrecto, lo verificamos
+ // por deporte.
if (!udp_checksum_ok())
goto drop;
+ print(0x0008);
+
+ // Terminamos recepción
netdev_recv_end();
+ print(0x0010);
// Respuesta
netdev_send_start();
eth_write_frame_header();
- //udp_dgram_len = UDP_HEADER_SIZE+len;
- //ip_packet_len = IP_HEADER_SIZE+udp_dgram_len;
+ ip_packet_len = UDP_HEADER_SIZE + len;
+ printb(ip_packet_len, 0x20);
ip_write_packet_header();
+ udp_dgram_len = len;
+ printb(udp_dgram_len, 0x40);
udp_write_dgram_header();
- netdev_write_start(len);
- for (i = 0; i < len; ++i)
- udp_write_byte(leds_matrix[i]);
- netdev_write_end();
- udp_write_checksum(ETH_HEADER_SIZE+IP_HEADER_SIZE);
- netdev_send_end(ETH_HEADER_SIZE+IP_HEADER_SIZE+udp_dgram_len);
+ elp_write_response();
+ udp_write_checksum(ETH_HEADER_SIZE + IP_HEADER_SIZE);
+ netdev_send_end(ETH_HEADER_SIZE + IP_HEADER_SIZE
+ + UDP_HEADER_SIZE + len);
+ printb(ETH_HEADER_SIZE + IP_HEADER_SIZE
+ + UDP_HEADER_SIZE + len, 0x80);
+ //XXX
+ if (elp_command.set && (elp_command.var == ELP_VAR_PAUSE))
+ TR2 = 1;
}
}
continue;