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á)

No hay comentarios:

Publicar un comentario