Como el objetivo es que el telescopio ,además, se mueva, tendremos que incluir de alguna manera , el código en lenguaje de programación convencional (C,C++,Java,Ruby) en nuestra definición Ragel .
Para ello definimos acciones, esto consiste simplemente en asignar un identificador a un trozo de código.
A modo ejemplo soso y tontorrón de libro de texto:
action print_hello {printf("hello action %d \r\n",number++);} action print_bye {printf("bye action %d \r\n",++number);} action do_for {int i;for (i=0;i<=100;i++) printf("el valor del contador es %d\r\n",i);}Hemos definido tres acciones,las dos primeras imprimen un mensaje e incrementan el valor de una variable y la tercera es un bucle for que imprime de cero a cien.
Es mejor que añadamos algo que sea realmente útil para variar la cantidad de momento angular de nuestros cacharritos,para ello definimos las siguientes acciones:
- move_dir :Mover telescopio.
- "action move_dir {move(stcmd);}"
- change_rate:Cambiar velocidad seleccionada.
- "action change_rate {rate(stcmd);}"
- goto:Ir a coordenadas destino.
- "action goto {go_to;}"
- storecmd:Almacenar carácter que activa la transición.
- "action storecmd{stcmd=fc;}"
La asignación stcmd=fc; es una simple sentencia en la cual stcmd seria una variable local de tipo char, en ella almacenamos para uso posterior el carácter de la transición en curso.
La definición de la sintaxis de Move se modifica a:
Move = 'M' ([nswe]@storecmd %move_dir | 'S'%goto)
- La expresión @storecmd indica que al recibir un carácter que pertenezca al conjunto ['n','s','w','e']se almacena el carácter en la variable stcmd.
- La acción %move_dir invocara la función move ,el valor almacenado en stmdc es el parámetro que determina la dirección seleccionada.
- Del mismo modo se invocará la función go_to si el carácter recibido es 'S'.
En este caso lo hacemos así para que la acción se ejecute siempre que se reciba el carácter terminal '#'
El mismo análisis es aplicable a la definición de las sintaxis y acciones de Rate
Para ilustrar porque es interesante utilizar Ragel como herramienta para este tipo de tareas se muestra el código Ragel empotrado en la función que procesará la entrada y a continuación el código en C de la implementación de un parser correspondiente a los comandos básicos LX200 que se usa en el PicGoto estándar el cual esta programado "a tecla" sin usar ninguna herramienta.
Creo que es evidente cual de ellas es mas fácil de mantener y ampliar.
En posteriores entradas (si alguien llegó hasta aquí) veremos como procesar el formato coordenadas sexagesimales y horarias.
long lx200( char *str ) { char *p = str, *pe = str + strlen( str ); int cs; char stcmd; char neg = 1; //---------------------------------------------------------------------------------------- %%{ machine lx200; write data; }%% %%{ #Acciones action move_dir {move(stcmd);} action change_rate{rate(stcmd);} action goto {GOTO;} action stop {;} #definicion sintaxis LX terminos auxiliares Move = 'M' ([nswe]@storecmd %dir | 'S'%Goto); Rate = 'R' [CGMS] %rate; main := ':' (Rate|Move) '#'; # Initialize and execute. write init; write exec; }%% //----------------------------------------------------------------------------------------- if ( cs < command_first_final ) // fprintf( stderr, "LX command: error\n" ); return neg; };
Ahora el código que implementa lo mismo en C pelón, picado a mano.
if (RCIF) { buffer = RCREG; switch (state) { /* algunos estados despues . . . . . . . */ //Estado 8 comienzo detección comandos basicos LX200 case 8: state = 0; if (buffer == ':') state = 9; if (buffer == '#') state = 8; break; //Estado 9 comienzo identificacion comandos basicos LX200 case 9: state = 0; switch (buffer) { case 'M': ra_speed = ra_current_speed; dec_speed = dec_current_speed; dire = 1; halt= 0; state = 10;; break; case 'Q': ra_speed = 0; dec_speed = 0; dire = 0; state = 10; break; case 'R': state = 10; guide = 0; break; case 'F': state = 14; break; } break; //Estado 10 lectura Comandos movimiento y seleccion de velocidad LX200 case 10: state = 0; switch (buffer) { case 'w': if (dire == 1) ra_current_mstep_period = ra_speed; else { ra_current_mstep_period = ra_speeds[4]; dire = 1; } ; ra_dir = dire; break; case 'e': if (dire == 1) { ra_current_mstep_period = ra_speed; if (guide){ ra_current_mstep_period = ra_speeds[5]; if (ra_speeds[5] <= ra_speeds[4]) dire=-1; } } else { ra_current_mstep_period = ra_speeds[4]; dire = -1; } ra_dir = -dire; break; case 'n': dec_current_mstep_period = dec_speed; dec_period_counter = 0; dec_dir = dire; if (dire == 0) PORTB = (9 & frev); break; case 's': dec_current_mstep_period = dec_speed; dec_period_counter = 0; dec_dir = -dire; if (dire == 0) PORTB = (9 & frev); break; case 'G': ra_current_speed = ra_speeds[3]; dec_current_speed = dec_speeds[3]; guide = 1; break; case 'S': ra_current_speed = ra_speeds[0]; dec_current_speed = dec_speeds[0]; break; case 'M': ra_current_speed = ra_speeds[1]; dec_current_speed = dec_speeds[1]; break; case 'C': ra_current_speed = ra_speeds[2]; dec_current_speed = dec_speeds[2]; break; default: state = 0; break; } break; case 11: state = 0; break; //Estado 13 conmutacion manual medios pasos ,micropasos case 13: RB3=led=(buffer<64) ; if (led) {half_ra_bit=half_de_bit=0; TMR2IE=1; frev = frev | 0x08; } else {half_ra_bit=half_de_bit=1; TMR2IE=0; frev=frev & 0xf7;} state = 0; break; //Estado 14 lectura Comandos Enfoque LX200 case 14: state = 0; switch (buffer) { case '-': focuser_run_bit = 1; frev = 0xff; RB0 = 1; break; case '+': focuser_run_bit = 1; frev = 0xfe; RB0 = 0; break; case 'Q': focuser_run_bit = 0; break; case 'F': focuSpeed = hifocuSpeed; break; case 'S': focuSpeed = lowfocuSpeed; break; default: state = 0; break; } break;
No hay comentarios:
Publicar un comentario