ayudita mejora tabla de saltos [SOLUCIONADO]

hola amis:
para mi invento he hecho unos comandos, los envio por consola, y el ardu los interpreta y ejecuta.

la 1ª idea fue una cascadas de:
if(bufer_entrada =="ORDEN1"){ orden1(); }
,,,, con todas las ordenes,
esto me ahorraria mucho tiempo, pero no memoria ni me parece elegante.

2ª idea: una tabla de saltos. con una compacta rutina de comparacion,

void (*pf[ordenes_top])(void) = {//ESTA ES LA TABLA DE SALTOS
_in_OFF, //MANTENER SINCRONIZADOS LOS SALTOS CON CADENAS DE COMPARACION, (EN .H)
_in_ON,
_in_AUTO_T,
_in_AUTO_N,
} //hay otras 40 mas

char ordenes[][ordenes_top]= {//MANTENER SINCRONIZADOS LAS CADENAS DE COMPARACION, CON TABLA DE SALTOS
//CONTROL ACCION
"OFF", //stop, unica permitida en ejecucion
"ON", //reset y pone a ejecutar
//DEFINIR ACCION
"AUTO T=", //"AUTO T=ho:mi:se" def. t entre vendimias, MIN 3seg
"AUTO N=", //"AUTO N=12" define numero de vendimias, de 00 a 99
}

,,, ordenes[k][in_ptr] //k es el numero de orden, in_ptr es el puntero del interprete a la letra a comparar
,,, pfk; //ESTE ES EL SALTO DE LA TABLA DE SALTOS

la cosa funciona bien en el prototipo de 4 ordenes, con las 40 peta el UNO, no el MEGA, por lo que supongo que agota memoria

3º idea, meter las cadenas de comparacion en memoria de programa, creo que era (por algun rar lo tendre,,,)
PROGMEM void (*pf[ordenes_top])(void) = {,,,,
y el caracter se leia con un pgm_read_byte( ordenes[k][in_ptr]);

4º idea, como hay que tener sincronizadas la tabla de saltos y de comparaciones, y son dos separadas, pense que seria mejor agruparlas en una estructura:

typedef void (*fptr) (void); //luego cuento esto

PROGMEM struct {
void (*pf)(void); //salta a una funcion generica
char ordenes[10]; //string de orden generica MAX 9 caract, mejor 8
}tabsal[ordenes_top] = { //tabla de saltos [numero de ordenes, definido en .h]
_in_off, "off", //salto a of(); , y su orden
_in_on, "on", //salto a on(); y su orden
_in_auto_t, "auto t=",
_in_auto_n, "auto n=",
};

mem = tabsal[k].ordenes; //mem lleva la direcion donde empieza la orden[k]
bucle(){,,,,,
in_k=pgm_read_byte(mem); //lee de memo prog
mem++;

el interprete funciona perfecto. el problema viene cuando ha de saltar. que siempre me saluda tras reset.
antes sin progmem con un pfk; arreglado. pero ahora hay que leer el salto de la progmem al igual que los caracteres de comparacion.
buceando por google di con uno que tenia problema con esto al migrar a atmegas grandes.
segun deduje tengo que poner

f = (fptr)pgm_read_word(tabsal[k].pf);
f();

por eso el typedef void (*fptr) (void); antes de la estructura
parece que carga la direcion de salto a otra funcion generica normal, y salta a traves de ella.

ayer y hoy me pase el dia estudiando el tema, no hay manera,

en tools\avr\bin hay un aladino que uso como consola,
tel temporal donde trabaja el ardu copio alli el .elf
escribo avr-objdump -h -S demo.elf > demo.lst
y me aparece un .lst que es desensamblado

PERDON CONFUNDI ENTRE VARIOS DESENSAMBLADOS QUE TENIA, ESTA MEJOR DE LO QUE CREIA.

000008f6 <tabsal>:
     8f6:	b2 04 6f 66 66 00 00 00 00 00 00 00 b4 08 6f 6e     ..off.........on
	...
     90e:	f9 07 61 75 74 6f 20 74 3d 00 00 00 eb 07 61 75     ..auto t=.....au
     91e:	74 6f 20 6e 3d 00 00 00                             to n=...

00000926 <__ctors_end>:

HAY ESTA MI TABLA DE SALTOS
segun esto empieza en 08f6, con su salto a 04b2 y su off sobre 10 caract, salto a 08B4 y su on, 07F9 y su auto t=, 07EB auto n=

       f = (fptr)pgm_read_word(tabsal[1].pf);
     fbe:	84 eb       	ldi	r24, 0xB4	; 180
     fc0:	98 e0       	ldi	r25, 0x08	; 8
     fc2:	fc 01       	movw	r30, r24
     fc4:	25 91       	lpm	r18, Z+
     fc6:	34 91       	lpm	r19, Z+
      f();
     fc8:	f9 01       	movw	r30, r18
     fca:	09 95       	icall
      
	_interprete_fin:

esto el desemsamblado del salto, observese que no es a una K generica, sino que la cambie a 1 para simplificar el codigo.
segun esto el salto a orden [1], que es "on", esta en 08b4
segun mis cuentas esta en 0902, ¿NO?, donde dice él cae en mitad de la parrafada de la orden help.

00000964 <_Z7_in_offv>:
00001168 <_Z6_in_onv>:
00000fd6 <_Z10_in_auto_nv>
00000ff2 <_Z10_in_auto_tv>:
y estas son la direciones donde estan las rutinas
que son el doble de lo que pone en la tabsal, puede ser.

una de mis ordenes estandar es PEEK, me fue util variarla para que me dijese que numerito devuelve pgm_read_word(tabsal[k].pf)
lo dificil, que aun no controlo, es interpretar el tipo,

unsigned int addr;
addr = (fptr)pgm_read_word(tabsal[1].pf); invalid conversion from 'void ()()' to 'unsigned int'
addr = pgm_read_word(tabsal[1].pf); compila sin problema
addr =tabsal[1].pf; invalid conversion from 'void (
)()' to 'unsigned int'
addr =(int)tabsal[1].pf; compila sin problema
ya no recuerdo y las tengo desmontadas ahora, pero cuando no daban siempre ffff, daban unos numeros rarisimos por disparatados, siempre los mismos para cada orden.

EDITADO: SOLUCIONADO

faltaba el & dolar, como explican PROGMEM - Arduino Reference

f = (fptr)pgm_read_word(&(tabsal[1].pf));
fbe: 82 e0 ldi r24, 0x02 ; 2
fc0: 99 e0 ldi r25, 0x09 ; 9
fc2: fc 01 movw r30, r24
fc4: 25 91 lpm r18, Z+
fc6: 34 91 lpm r19, Z+
f();
fc8: f9 01 movw r30, r18
fca: 09 95 icall

ahora ya apunta a 0902

Hola,

Yo estoy haciendome un interprete también... A lo mejor podríamos intercambiar ideas.
Los comandos los guardo en flash, como has puesto por ahí. Me he creado unas rutinas (scan, recoger número, recoger comando, recoger variable, etc.).
La rutina de scan busca tokens conocidos sobre la posición actual de entrada, o quita espacios, etc.
No uso puntero a funciones.

Tampoco se puede usar expresiones del tipo ((A+B)*C)... etc.
Siempre se realizan sobre variables del sistema que dejo al usuario (los llamo registros). He creado unos float R01...R20 y todos los comandos usarán dicho registros para hacer operaciones, etc (tipo ensamblador).
Los que he visto por internet, suelen pasar la expresión a notación posfija y usan una pila, pero lo veo más díficil para que alguien lo cambie a su antojo.

Por ejemplo: AR 1 R01 -> esto me hace un R01=analogRead(1).
Otros son DWH 1 -> digitalWrite(1,HIGH) ó DWL 1 ->digitalWrite(1,LOW).

Pero bueno.... estoy abierto a ideas!! Quiero que sirva para pasar los comandos desde serie, guardados en una memoria externa o EEPROM, recibidos por bus CAN, ethernet,etc.

Mi primera aplicación va a estar orientada para trabajar por bus CAN.

Existe Bitlash que esta muy bien, aunque por entretenimiento me lo estoy haciendo yo :smiley: (http://bitlash.net/wiki/start )

Saludos

Igor R.

OH! gran honor me pidan ideas.

lo tengo hecho, pero incrustado en gran proyecto, trabajo en demo.

es mas sencillito, solo interpreta, por la noche ocurrir comodines poner.

hoy me queda 1 hora libre. no creo acabe, subo borrador en 1 hora.

ES BORRADOR

/**********************************************/
/*   I N T E R P R E T E   C O M A N D O S    */
#include <avr/pgmspace.h>	//nesario por usar PROGMEM, pgm_read_byte,,

#include "interprete.h"		//decaraciones y definiciones propias de este fichero
#include "main.h"		//_ma_off, _ma_on,,, declaradas alli
#include "comandos.h"		//muchos comando alli def
#include "help.h"		//

typedef void (*fptr) (void); 	//define una funcion generica 

/**********************************************/
/*  P O N E R   R U T I N A   Y   S A L T O   */
PROGMEM struct {		//estrucutura contiene_
	void (*pf)(void);		//salto a funcion asociada
	char coman[10];		//letras comando asociado ! ! ! MAX 9, mejor 8
	}tabsal[coman_top] = {	
	//con la estructur ahago una matriz, EN 'coman_top' PONER CUANTAS SON, esta en .h
		_ma_off,	"off",
		_ma_on,  	"on",		//Y POR AQUI PONGO LOS PARES
		_co_rom_pre,	"rom?",		//NOMBRE DE FUNCION Y LETRAS
		_co_ram_pre,	"ram?",
		_co_ram_igu,	"ram=@@@@",	//@ ES COMODIN, NO COMPRUEBA, 
		_co_ram_pok,	"poke=@@",	//pueden variar por ser cifras
		_ma_eco_0,	"eco 0",
		_ma_eco_1,	"eco 1",
		_help0, 	"help",
		_help0, 	"h",
		_help1, 	"help 2",
		_help1, 	"help 2",
		};//PONER EN coman_top (esta en .h) CUANTAS SON



/**************************************/
/******     N U C L E O         *******/
void	_interprete_patrulla(void){	//NUCLEO DEL INTERPRETE DE COMANDOS
	fptr f; //crea una funcion generica del tipo definido como fptr, no idea, sacao internet
	if(rs_dat_RX!=0x0A){	return;}	//no llego final de parrafo
	if(rs_ptr_RX < 3){			//si solo llegaron 0x0d y 0x0a
		goto _interprete_fin;}			//termina
	for(k=0;k<coman_top;k++){		//en k el numero de comando
		in_ptr=0;				//ptr a 0
		mem = tabsal[k].coman;			//mem apunta a inicio tabsal[k].coman en la progmem
		while (1) {				//bucle
			in_pgm=pgm_read_byte(mem);		//lee de memo prog
		//	in_pgm=pgm_read_byte(&(mem));		// C O M P R O B A R   funciona sin &
			in_buf=rs_bufer_RX[in_ptr]		//in_buf = letra a comparar, matrices lentas
			in_ptr++;				//apunta a siguiente en bufer
			mem++;					//apunta a siguiente en progmem
			if(!in_pgm){	//if(in_pgm==0){	//llego al final?
				if( in_buf == 0x0D){			//termino en el bufer //sobra, porsi
					goto _interprete_ok;}			//si, antes coincidio, OK
				if( in_buf == 0x0A){			//termino en el bufer
					goto _interprete_ok;}			//si, antes coincidio, OK
				goto _interprete_over_dato;		//OTRO GOTO, VIVA RICHIE
				}
			if( in_pgm == '@'){			//llego comodin?
				continue;} 				//si, a por otra letra
			if( in_buf == 0x0D){			//termino el bufer?
				break;} 				//si, a por otro parrafo
			if( in_buf == 0x0A){			//termino el bufer?
				break;} 				//si, a por otro parrafo
			if( in_buf != in_pgm){			//coincide?
				break;} 				//no, a por otro parrafo				
			}	
		}//NO ENCONTRO COINCIDENCIA
		
	_interprete_over_dato:				//se paso de letras
		Serial.print("demasiadas letras\n");
		_bufer_reset();					//vacia bufer
		return;						//return para no hacer lo que sigue
	
	_interprete_mal:				//interprete mal
		Serial.print("mal comando, type HELP\n");
		_bufer_reset();
		return;
	
	_interprete_ok:					//interprete OK
		//Serial.print("_interprete_ok\n"); 	
	      
		f = (fptr)pgm_read_word(&(tabsal[k].pf));	//ESTE ES EL MEOLLO DEL ASUNTO
		f();
			//NO LO ENTIENDO BIEN, ES REFRITO DE RECORTES DE INTERNET
			// tabsal[k].pf aqui esta la direcion de inicio de la rutina
			// el & ¿fuerza la direcion?, no entiendo, 2 dias duro me llevo ponerlo
			// pgm_read_word(&(tabsal[k].pf)); como todo esta en progmem, lo lee
			// (fptr)pgm_read_word(&(tabsal[k].pf)); ¿fuerza a que el numero devuelto 
			//     sea del tipo funcion generica (fptr)?
			// el tipo 'fptr', es 'normal', no es que este en ram, pero tampoco esta 
			// fosilizada en la progmem, ella copia el fosil
			// f es una del tipo (fptr), por eso puede recibir el vector, carga escopeta
			// f() dispara
			// todo lo dicho son elucubraciones sin garantias 
			
		_bufer_reset();
		//return;	//es ultimo tonteria ponerlo			
	}

/**************************************/
/*       A U X I L I A R E S          */
void	_interprete_mal_num(void){
	Serial.print("mal numero\n");
	}	

unsigned char	_in_arro_d(char n){//ENTRA UN ASCII DE DECIMAL Y SALE COMO BYTE, o error
	in_buf=rs_bufer_RX[n];		//in_buf = letra a traducir a byte/2
					//uso in_buf por estar libre
	in_buf-=0x30;			//ver ascii wikip
	if(in_buf>9){			//
		bitSet(ma_error,poe);
		in_buf=0;
		}
	}	//si es que soy idiota, ¿pa que esto si solo hexas?, bueno ahora no lo borro

unsigned char	_in_arro_h(char n){//ENTRA UN ASCII DE HEXADE Y SALE COMO BYTE, o error
	in_buf=rs_bufer_RX[n];		//in_buf = letra a traducir a byte/2
					//uso in_buf por estar libre
	in_buf-=0x30;			//ver ascii wikip
	if(in_buf>9){			//puede tratarse de >9
		in_buf-=7;			//ver ascii wikip
		if(in_buf>15){			//
			bitSet(ma_error,poe);
			in_buf=0;
			}
		}
	}