jueves, 21 de febrero de 2013

Implementar LX200 (server) en C con Ragel (FSM compiler) sobre microcontroladores AVR (2)

Definiciones:

Empezamos por   lo mas sencillo seleccionar velocidad y mover el telescopio:
Comandos de selección de velocidad:
  • :RC# Seleccionar velocidad de Guiado (guide).
  • :RG#  Seleccionar velocidad de Centrado (center).
  • :RM# Seleccionar velocidad de Búsqueda.(find).
  • :RS# Seleccionar velocidad de Desplazamiento.(slew).
Comandos de movimiento y dirección:
  • :Me#  Mueve Telescopio al Este a velocidad seleccionada. 
  • :Mn#  Mueve Telescopio al Norte a velocidad seleccionada. 
  • :Ms#  Mueve Telescopio al Sur a velocidad seleccionada.
  • :Mw#  Mueve Telescopio al Oeste a velocidad seleccionada.
  • :MS# Mueve hasta  Objeto / Coordenadas Destino
    •  Devuelve:
    • 0  si el desplazamiento es posible
    • 1<cadena># Object Below Horizon
    • 2<scadena># Object Below Higher
Código Ragel mas simple que reconoce las expresiones:
%%{
 machine LX200;
 write data;
}%%
//Definicion comandos 
%%{
Rate ="R" [GCMS];
Move = "M" [enswS];
main := ':' (Rate|Move) '#';
# Initialize and execute.
  write init;
  write exec;
 }%%

Traducida a lenguaje natural:
  • Rate:
    • Acepto cualquier cadena que empieza por la letra 'R'seguida de una 'G' o 'C' o'M' o 'S' .
  • Move:
    • Acepto cualquier cadena que empieza por la letra 'M'seguida de una 'e' o 'n' o 's' o'w' o 'S' .
  • main:(Regla principal)
    • Acepto cualquier comando Rate o Move si van precedidos de ':' y les sigue '#';
Y aquí el grafo de la máquina de estado finito que reconoce el lenguaje.





Reconocer comandos está muy bien pero no suele ser suficiente,  además queremos que estos tengan algún efecto en el mundo real.
Veremos como en la próxima entrada.

martes, 12 de febrero de 2013

Implementar LX200 (server) en C con Ragel (FSM compiler) sobre microcontroladores AVR (1)


Mi intención es dedicar unas cuantas entradas a explicar la implementación si aprecio que existe algún interés ya que es mas trabajoso explicarlo que hacerlo. Últimamente los proyectos de cacharreo astronómico nacionales son muy  escasitos...Y no:  AVR != Arduino.

LX200  es un protocolo, propiedad de fabricante de  equipamiento astronómico Meade Instrumentscuyo objeto es el control de telescopios astronómicos.
Adopta   el  modelo cliente-servidor ,siendo el dispositivo cliente generalmente un PC  ,o Tablet ,el cual ejecuta software de planetario o adquisición de imágenes.
El servidor suele esta implementado  en el firmware del telescopio(montura).
En otros casos puede implementarse parcialmente un traductor en el lado del cliente como se hacia con la versión estándar de PicGoto.

Esto sería una conversación de inicio de sesión típica con su traducción al español   :

Cliente: :Ga:#:Gt# (¿Donde  estás?) 
Servidor: +36*50#-002*50#  (En Almería.)
Cliente:::Sg +36*43#:St-004*12# (Eso fue ayer.Ahora estás en Benajarafe.)
Servidor 1 (vale)
Cliente::SL23:15:00# (Son las once y cuarto.) 
Servidor 1 (vale)
Cliente:::gT#(Te enciendo el GPS por si no te fías.)
Servidor: 1 (Gracias,Ya estoy orientado.)  
Cliente: :GR#:GD# (¿Donde estás apuntado? )
Servidor:  :05:15:10#-08*11'14#  (A las coordenadas del Rigel.)
Cliente :  :Sr13:26:48#:Sd-47*29'00# (Te paso las  coordenadas de omega centauri.) 
Servidor:  00 (Está bajo el horizonte , prepara el detector de neutrinos.)
Cliente : :MS# ¡Apunta allí ahora !
Servidor:  1 (No, paso, lo del detector era broma ,no apunto ni loco, que me rompo)

Se puede consultar el conjunto completo de comandos y respuestas en LX200  


El objetivo es implementar un intérprete de LX200;n o por gusto,sino porque es el protocolo más extendido y por estar lo suficientemente mal diseñado como para que tenga sentido emplear un lenguaje de especificación de maquinas de estado finito  como  Ragel .

Frente  a otras herramienta muy extendidas como Lex o, el código generado es lo suficientemente  ligero y rápido  para ser usado con microcontrolador y pequeños sistemas embebidos.
El compilador de Ragel genera código sin dependencias de librerías externas  en C,D,Java o Ruby.

Las ventajas  sobre  programar directamente dicha  máquina de estados en C son varias:
  • Se usan expresiones regulares para describir la maquina y sus componentes.
  • Se asocian acciones (trozos de código nativo) a las transiciones entre estados
  • Es mas fácil de mantener, ampliar modificar y corregir.
  • Puede  generar diagramas gráficos de máquina que facilitan el análisis y la detección de errores.
El digrafo siguiente es la representación gráfica generada a partir de la maquina de estado que esta descrita en el bloque de código posterior. Es una implementación minimalista del protocolo LX200 incluyendo  comandos básicos de apuntado,guiado,puesta en hora,sincronización ...













Aunque cacho de código Ragel siguiente parezca  un truño infumable, lo es mucho menos que su implementación directa  en C. 

%%{
 machine command;
 write data;
}%%


        

 %%{
  #Acciones 
  action getgrads {ADD_DIGIT(deg,fc); }
  action getmin {ADD_DIGIT(min,fc); } 
  action getsec {ADD_DIGIT(sec,fc); } 
  action neg { neg=-1;} 
  action dir {move(stcmd);}
  action Goto {GOTO;}
  action stop {;}
  
  action rate { RATE;}
  
  action return_ra { lxprintra(mount.current_ra);}
  action return_dec {lxprintde( mount.current_dec);} 
  action return_ra_target { lxprintra(mount.ra_target);}
  action return_dec_target {lxprintde( mount.dec_target);} 
  
  action return_sid_time { ;}
  action sync {mount.current_dec=mount.dec_target;
        mount.current_ra=mount.ra_target;
                          rprintf("synced#");}
        
  action settargetra { set_target_ra( deg,min, sec);} 
  action settargetde { set_target_de( deg,min, sec,neg);}
        action rafrac {deg+=(fc-'0')*6;}
  action return_local_time { ltime();}
  action set_cmd_exec {set_cmd_exe(stcmd,(neg*(deg )));}
  action addmin {deg=deg*3600+min*60;}
        action addsec {deg+=sec;}
  action storecmd {stcmd=fc;}
  
  #definicion gramática  LX terminos auxiliares
     sexmin =  ([0-5][0-9])$getmin@addmin ;
     sex= ([0-5][0-9] )$getsec@addsec;
  deg =(([\+] | [\-]@neg)  |  digit @getgrads) (digit @getgrads){2} "ß"  sexmin ([:\']  sex)? ;
        RA = ([0-2] digit) $getgrads   ':' sexmin ('.'digit@rafrac | ':' sex) ;
  #Definicion gramática comandos
     Poll= 'G'( 'R'%return_ra | 'D'%return_dec |'r'%return_ra_target | 'd'%return_dec_target | 'L'%return_local_time |'S'%return_sid_time); 
     Move = 'M' ([nswe]@storecmd %dir | 'S'%Goto);
     Rate = 'R' [CGMS] %rate;
     Set='S' (([dazgt]@storecmd ' 'deg ) | ([rLS]@storecmd ' ' RA))%set_cmd_exec ;
  Sync = "CM"%sync; 
  Stop ='Q' (''|[nsew])@storecmd %stop;

   main := (':' (Set | Move | Stop|Rate | Sync | Poll)) '#'  ;


  # Initialize and execute.
  write init;
  write exec;
 }%%

Lo he compilado con AVR-GCC para un ATMEGA128L y pasa como un telescopio verdadero para la implementación ASCOM de LX200.


(continuará)