Más preguntas respecto a la creación de librerías

Hola a todos. Las preguntas son respecto a otra librería que llevo en proceso (más una extra), que creo que ya algunos saben a qué me refiero:

¿Cómo aplico correctamente la herencia? Traté de que mi clase heredara de Print (le agrega los famosos print y println), pero parece que el compilador entra en conflicto con una función de Print que se declara con la palabra virtual. ¿Qué significa eso? ¿Que es abstracta?.
Cuando lo intenté corregir, ahora el compilador no me dejaba instanciar la clase porque cree que es abstracta.

Intento imitar put y get de EEPROM, pero no me sale. Ya veo que no es solo de copiar la cabecera y hacer las modificaciones pertinentes. La idea es recuperar/guardar cualquier tipo de dato utilizando una "plantilla", pero evidentemente no sé usarla ::slight_smile:

¿Es posible "finalizar" una tarjeta SD por software? Hasta lo que llego a comprender de Sd2Card (el corazón de la librería SD), hay cómo inicializar una tarjeta; pero no lo contrario. Por el lado de hardware es simple: remover/cambiar la tarjeta solo cuando no es accesada; ¿pero por software? ¿Será entonces que solo destruyendo el objeto y creando otro nuevo?

Ahora una pregunta extra y termino: creo un programa y le doy a "Verificar"; el compilado termina. Si luego conecto el Arduino al PC y le doy a "Subir", ¿por qué vuelve a compilar aunque no haya modificado ni el código ni las configuraciones?.
Dicho en otras palabras: ¿por qué vuelve a compilar aunque ya lo haya verificado?

En muchos tutoriales sobre Arduino, he observado que primero verifican y luego suben; pero al subir no vuelve a compilar, sino que va inmediatamente a ese paso.
Para alguien como yo que todo lo hace en una "netbook" de 4 años de antigüedad, es irritante compilar dos veces cuando este proceso se tarda mínimo 30 segundos; incluso compilar algo tan simple como Blink, me toma entre 45 segundos y 1 minuto.

Y por supuesto que no lo olvido: agradecer de antemano cualquier respuesta :slight_smile:

Ups, olvidé agregar otra pregunta más:

Olvidé cómo "autoinstanciar". En otra ocasión lo que hice fue algo como:

extern Clase nombre;

Y lógicamente me había funcionado. Lo intento así de nuevo y ahora el compilador se queja -_- ¿Qué he hecho mal?

Buenas again..

Sobre las funciones virtuales hay una explicación muy buena en stackoverflow (no encuentro el link, estuve leyendo mucho en torno al tema), pero lo que viene al caso son las funciones virtuales puras (no sé si en español es así; pure virtual).
Las funciones virtuales puras hacen que la clase no sea instanciable, que sea abstracta. Usualmente se utiliza para crear interfaces o hacer clases como Print o Stream, que definen un set de instrucciones (pero que una parte debe implementarla quien la utilice).

Para poder instanciar una clase heredada de la que contiene la función virtual pura, uno debe definir todos esos métodos; sino, el compilador también la definirá como abstracta, y otros podrán utilizarla, siempre, bajo las mismas premisas.

Otro tema; sobre lo de las plantillas, te puedo dar una mano, nunca lo implementé más allá de algunas cosas simples, pero debería ser sencillo en este caso si te manejás con operaciones a nivel de bit y entendés cómo están estructurados los diferentes tipos de datos. Skype podría darnos una mano :stuck_out_tongue:

Habría que buscar en la hoja de datos de alguna SD referencias en cuanto a la detención de la misma (ojo, la tarjeta cuando la usamos con arduino la usamos en modo SPI/MMC, no modo SD).

Sobre lo último (y sí, nótese que no ando con muchas ganas de "quotear"), en realidad, la mayoría de las veces no lo hace; o sólo compila el script principal (el .ino). Cuando cambias de board (a otro tipo, attiny por ejemplo), el compilador tiene que recompilar absolutamente todo el núleo del arduino, porque muchas cuestiones a nivel del procesador, cambiaron. Si uno está testeando una biblioteca, a veces pueden generarse problemas a partir de este caché, que no recompila las bibliotecas usadas a pesar de que uno recompile el script. No recuerdo dónde es que la IDE aloja los archivos temporales de la configuración (usualmente utilizo Sublime Text + Stino); pero no es algo que google no pueda resolver).
Lo que no estoy seguro es sobre tu pregunta jajajaja, pero tengo entendido (estoy casi seguro) que al compilar, si el .ino no cambió, no se recompila absolutamente nada. Inclusive en Sublime, si ya compilé previamente y no modifiqué nada, simplemente comienza la carga. ¿Qué versión de la IDE estás usando?

Saludos, y, estaremos en contacto estos días :stuck_out_tongue:

===============
Edito, extern lo que hace es incluir una referencia de otro archivo en el actual. Si en a.cpp tienes una variable definida, y habiendo incluído todos los .h y .cpp correspondientes intentas utilizarla desde b.cpp, no podrás, a menos que la incluyas con un extern.
Nunca lo había visto utilizado para instanciar una clase; en realidad, ni siquiera de caer en a qué te refieres con autoinstanciar, a menos que sea crear una sola instancia global (estática, en realidad) de la clase (estilo el objeto Serial).

Saludos de nuevo!

ferminolaiz:
Para poder instanciar una clase heredada de la que contiene la función virtual pura, uno debe definir todos esos métodos; sino, el compilador también la definirá como abstracta.

Y la pregunta es: ¿cómo? El problema se ve así:

virtual size_t write(uint8_t) = 0;

El "= 0" es el que la vuelve abstracta (virtual pura); seguramente por ser la base del resto de funciones. No todos los "streams" colocan bytes de la misma manera.
Ese no debería ser un problema, se supone que ya tengo una implementación así:

bool write(int b);

Pero el detalle es: ¿cómo combino una cosa con la otra para así implementar dicha función como Print y el compilador lo mandan?

ferminolaiz:
sobre lo de las plantillas, te puedo dar una mano, nunca lo implementé más allá de algunas cosas simples

¿Simples como qué? ¿En clases?
No sé que tan difícil es de recrear, pero lo que hacen put y get es recibir una variable por referencia; de esta forma trabaja directamente en la porción de memoria en vez de retornar un valor o hacer una copia. Con el tipo de dato en el parámetro es donde se determina cuántos bytes hay que leer/escribir.
Lo del paso por referencia es interesante, porque por alguna razón no hay que dársela explícitamente; bastaba con el nombre de la variable. Ejemplo:

EEPROM.get(0, variable); // Referencia implícita
EEPROM.get(0, &variable); // Referencia explícita

ferminolaiz:
Habría que buscar en la hoja de datos de alguna SD referencias en cuanto a la detención de la misma

Finalización por hardware se me ocurría que se le enviaba un comando que lo reiniciase por completo, hasta el punto de necesitar ponerlo en modo SPI otra vez. De no existir, no queda de otra que apagar el sistema o retirar la tarjeta.
Si el medio físico ya se inicializó pero el objeto de Sd2Card no lo ha registrado así todavía, ¿reintentarlo en ese estado haría que el proceso falle? De ser así, entonces obligaría al usuario a retirar la tarjeta; caso contrario, se podría re-inicializar sin sacar nada.
Si Sd2Card no implementa método de finalización alguno, entonces no me queda más remedio que destruirlo y crear otro nuevo.

Esta característica debería servir para dar una "extracción segura"; permitiendo el cambio "en caliente".
De hecho, en mi librería básicamente todo es inservible hasta que la tarjeta sea inicializada correctamente (eso incluye que se pueda reconocer la capacidad de la misma; si no se puede, no cuenta).

ferminolaiz:
la mayoría de las veces no lo hace; o sólo compila el script principal (el .ino).

Si no le he cambiado absolutamente nada, no debería recompilar aún después de la verificación.

ferminolaiz:
Si uno está testeando una biblioteca, a veces pueden generarse problemas a partir de este caché, que no recompila las bibliotecas usadas a pesar de que uno recompile el script.

Con la IDE de Arduino aparentemente no hay problemas con eso; o al menos es así cuando todos los archivos están en la misma carpeta, de lo contrario los errores de compilación no cambiarían cada vez que intento corregir algo.

ferminolaiz:
pero tengo entendido (estoy casi seguro) que al compilar, si el .ino no cambió, no se recompila absolutamente nada.

Eso es lo que digo yo :I

ferminolaiz:
¿Qué versión de la IDE estás usando?

1.6.7

ferminolaiz:
Nunca lo había visto utilizado para instanciar una clase; en realidad, ni siquiera de caer en a qué te refieres con autoinstanciar, a menos que sea crear una sola instancia global (estática, en realidad) de la clase (estilo el objeto Serial).

Esa es la idea.
"Autoinstanciar" está claro que no es un "término estandarizado", pero creo que habla por sí solo: significa que en la declaración de la clase (archivo.h) hay una instancia de sí misma. No en realidad dentro de la declaración, sino que dentro del mismo archivo y antes del último #endif

PDs:
Si logramos resolver el tema de put y get, pondré a prueba una característica que acabo de introducir: parseInt y parseFloat. Así es, esos que convierten texto a binario (variable) directamente desde el "stream" (toda la memoria de la tarjeta). Luego print y println hasta resolver lo de "virtual puro".

Cuando analicen mi librería, quizá más de uno me venga con que estoy "reinventando la rueda", y tienen razón.
En mi defensa, lo que no me gusta de Stream, es que las lecturas las hace con "timeout"; eso estaría bien pero cuando la longitud del "stream" es cambiante (ej.: el búfer de entrada del puerto serie). Pero para trabajar una tarjeta SD en forma "cruda", donde la capacidad (longitud del "stream") solo puede cambiar cambiando el medio físico... un "timeout" más bien entorpece el rendimiento del sistema.

Aquí es donde me doy cuenta que solo he tocado la punta del iceberg de C++.
En parte es irónico: manejo bien el tema de los flujos (de bytes), punteros de memoria y todo lo básico; pero nunca puedo crear una librería sin comenzar con al menos 3 errores de compilación.
En caso de que preguntes... este no es mi primer lenguaje de programación; de hecho, vengo de Java y no porque quise, sino porque en la universidad en la que estudio, se trabaja con ese lenguaje.

Pero el detalle es: ¿cómo combino una cosa con la otra para así implementar dicha función como Print y el compilador lo mandan?

El problema con la definición de write es que retorna size_t, y no bool. Siendo sinceros, el otro día me topé con size_t, lo googlee, y como tenía demasiadas cosas en el momento para hacer, fue a parar a marcadores. Pero, en sí eso es lo primero que me viene a la vista; habría que ahondar para ver qué significa realmente ese tipo.

El compilador, en sí, ve dos funciones que son diferentes.

¿Simples como qué? ¿En clases?
No sé que tan difícil es de recrear, pero lo que hacen put y get es recibir una variable por referencia; de esta forma trabaja directamente en la porción de memoria en vez de retornar un valor o hacer una copia. Con el tipo de dato en el parámetro es donde se determina cuántos bytes hay que leer/escribir.
Lo del paso por referencia es interesante, porque por alguna razón no hay que dársela explícitamente; bastaba con el nombre de la variable. Ejemplo:

Lo utilicé un par de veces para lo más sencillo, tratar diferentes tipos implícitamente, y poder definir el tamaño de un array dentro de una clase, en tiempo de compilación.

Lo de la referencia implícita en EEPROM.get(); creo que la resuelve automáticamente el compilador, no podría afirmarlo, pero lo he visto antes.

Con la IDE de Arduino aparentemente no hay problemas con eso; o al menos es así cuando todos los archivos están en la misma carpeta, de lo contrario los errores de compilación no cambiarían cada vez que intento corregir algo.

Claro, si cambias algo. Pero si sólo cambias código en la biblioteca (dentro de libraries/, no dentro de la misma carpeta) y no cambias nada del .ino, y vuelves a compilar, no recompila nada en realidad. Las cosas cambian si escribes algo, aunque lo borres luego. Si la IDE detecta cualquier cambio en el texto, recompila (al menos el .ino).
También tuve muchas veces problemas con archivos de configuración (.h) que mantengo por separado. Tenía errores que surgían de la nada, y era porque diez compilaciones atras yo había cambiado una línea del archivo de configuración, (en teoría el cambio no tenía efecto visible más alla de la legibilidad), y en realidad ese código estaba denrto del caché, y nunca se había recompilado. Un rato después, empezaban a aparecer cosas raras (en serio, muy raras) en el LCD, y yo sin haber tocado nada.

Gajes del oficio (?

Esa es la idea.
"Autoinstanciar" está claro que no es un "término estandarizado", pero creo que habla por sí solo: significa que en la declaración de la clase (archivo.h) hay una instancia de sí misma. No en realidad dentro de la declaración, sino que dentro del mismo archivo y antes del último #endif

Aaah, sí, lo vi hace un tiempo precisamente en HardwareSerial.h, ¿qué error te da al hacerlo? No creo que sea posible si el constructor espera algún parámetro...

Aquí es donde me doy cuenta que solo he tocado la punta del iceberg de C++.
En parte es irónico: manejo bien el tema de los flujos (de bytes), punteros de memoria y todo lo básico; pero nunca puedo crear una librería sin comenzar con al menos 3 errores de compilación.
En caso de que preguntes... este no es mi primer lenguaje de programación; de hecho, vengo de Java y no porque quise, sino porque en la universidad en la que estudio, se trabaja con ese lenguaje.

Me pasa todo el tiempo jajajaja, cada vez que me pongo a programar en serio encuento dos o tres cosas absolutamente nuevas, y bueno, así parece ser..

Yo vengo de... Ehm.. PHP.. :blush:

No me maten; eempecé hace unos 5 años y fui rondando entre muchos lenguajes hasta que llegué a PHP; me quedé ahí y logré manejar con cierta "soltura" las características del lenguaje (reflexión, por ejemplo) como para ponerme a escribir un programa sin pensarlo demasiado. El problema fueron mis primeras incursiones en C++ (desktop), el tipado estático me ganó, y lo dejé de lado.

No me di cuenta fue que con Arduino estaba programando en exactamente el mismo lenguaje, de a poco fui haciendo la transición. Lo gracioso es que después de un tiempo empecé a replicar un montón de las cosas que hacía antes (en cuanto a manejo dinámico de objetos, etc) en C++, con punteros y demás; cosas que tengo entendido están bien hechas (poneeele que sí :P), así que algo logré rescatar.

Pero nada, cuestión, te mando privado así vemos si quedamos un día de estos para poder chatear mínimamente y ver cómo va la cuestión.

Saludos!

Buenos dias,

Tengo un problema para poder hacer funcionar la placa arduino con el ordenador no la reconoce y me da error

El Sketch usa 3018 bytes (9%) del espacio de almacenamiento de programa. El máximo es 32256 bytes.
Las variables Globales usan 257 bytes (12%) de la memoria dinámica, dejando 1791 bytes para las variables locales. El máximo es 2048 bytes.
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x00
Problema subiendo a la placa. Visita http://www.arduino.cc/en/Guide/Troubleshooting#upload para sugerencias.

Si por favor alguien me puede ayudar.

Un saludo.

Hola.
No sé en qué punto te encuentras ahora mismo con tus dudas, Lucario. Si te puedo ayudar en alguna concreta, coméntalo por aquí.
Sólo por añadir un poco de luz sobre el tema de las funciones virtuales puras, son una especie de "todo:" (por hacer). Quiere decir que la clase que herede tendrá la "obligación" de definir ese método (de lo contrario la nueva clase seguirá siendo virtual, y por tanto no instanciable). Las funciones virtuales se definen de la forma "virtual tipo funcion(parámetros)". Si añadimos "virtual tipo funcion(parámetros)=0", será virtual pura.
En cuanto a tu write, como te indicó ferminolaiz, para implementar correctamente el método virtual puro, debe ser declarado como virtual size_t write(uint8_t) y definido como size_t write(uinto_t). Devolverá el número de bytes escritos (uno o cero).
Deberás implementar obligatoriamente ese método virtual puro, y opcionalmente redefinir otros métodos virtuales, si lo consideras necesario.
Echa un vistazo a esto.

@noter

El tema tiene la suficiente "chicha" como para hacer el ArduTip correspondiente ¿ no te parece ?

Estoy de acuerdo. De hecho la POO supongo que tendrá una sección propia. Aunque no me considero un profundo conocedor de la Programación Orientada a Objetos, pues me introduje de forma tardía, sí tenía pensado hacer alguna incursión en la materia, espero, sin meter la pata.

Muy bien entonces. Recapitulo:

  • Usar la misma cabecera de la función virtual pura para realizar la implementación.
  • Faltan por resolver: plantillas con paso por referencia implícito, finalizado de una tarjeta SD y el pre-instanciado.

El tema de las plantillas creo que noter una vez había propuesto algo para poder enviar/recibir cualquier tipo de dato mediante I2C, pero no recuerdo en qué hilo era.

El pre-instanciado si no lo soluciono, postearé el mensaje del compilador para si hay alguna pista que no haya notado.

El finalizado de una tarjeta SD, creo que lo voy a probar y luego les comento el resultado.

De momento no estoy en casa, así que por esta razón es que daré los resultados en el próximo post.

Si no me equivoco, lo de las plantillas era esto que mencioné aquí. ¿No?
Y lo de preinstanciar ¿es esto?

En cuanto a "cerrar" una tarjeta, supongo que de lo que se trata es de dejarla en un estado de no lectura/escritura (por tanto su CS en HIGH) con FLUSH previo de todos los datos alterados, especialmente del / los bloques donde vayamos a escribir nuestros índices de contenido (lo que llamaríamos la FAT).

noter:
Si no me equivoco, lo de las plantillas era esto que mencioné aquí. ¿No?
Y lo de preinstanciar ¿es esto?

Sí y sí.

Gracias a esas referencias, tengo casi todo resuelto (a menos que sea que el compilador se haya enfocado en un solo error).

Ahora la clase hereda de Print como es debido, las plantillas funcionan de maravilla y por alguna razón ahora el pre-instanciamiento funciona como en esa vez.

Ahora en put hay un error que la verdad no tiene sentido:

Arduino:1.6.7 (Windows 7), Placa:"Arduino Nano, ATmega328"

sketch\SdRaw.cpp: In member function 'unsigned int SdRawClass::put(long unsigned int, const T&)':

SdRaw.cpp:164: error: no matching function for call to 'SdRawClass::write(uint8_t*, size_t)'

   return write((uint8_t*)&t, (size_t)sizeof(t));

                                                      ^

sketch\SdRaw.cpp:164:54: note: candidates are:

In file included from sketch\SdRaw.cpp:1:0:

sketch\SdRaw.h:35:12: note: virtual size_t SdRawClass::write(uint8_t)

     size_t write(uint8_t b);

            ^

sketch\SdRaw.h:35:12: note:   candidate expects 1 argument, 2 provided

sketch\SdRaw.h:36:10: note: bool SdRawClass::write(long unsigned int, int) <near match>

     bool write(unsigned long p, int b); // Mimics the EEPROM function

          ^

sketch\SdRaw.h:36:10: note:   no known conversion for argument 1 from 'uint8_t* {aka unsigned char*}' to 'long unsigned int'


exit status 1
no matching function for call to 'SdRawClass::write(uint8_t*, size_t)'

Si heredo de Print, ¿por qué dice que no tengo definida la función write(uint8_t*, size_t)?
En la clase base, esta es virtual pero no pura.

noter:
En cuanto a "cerrar" una tarjeta, supongo que de lo que se trata es de dejarla en un estado de no lectura/escritura (por tanto su CS en HIGH) con FLUSH previo de todos los datos alterados

Eso. Lo que me deja en duda, es que si se puede dar por finalizada con solo el hecho de no ser accesada.

Lo de poner el CS en HIGH sé que invalidaría cualquier orden que se le envíe; pero si Sd2Card lo vuelve a dejar en estado LOW otra vez, entonces no tiene sentido alguno. Por esto tendré que ver si el objeto se puede seguir utilizando, o lo tengo que descartar.

PD: creo que bool SdRawClass::write(long unsigned int, int) lo podemos ignorar como parte del error. write está sobrecargado cuatro veces, tres de ellas piden dos parámetros; y por alguna razón el compilador confunde "puntero de unsigned char" con unsigned long.

Si sigues sin poder solucionarlo, pon el código actual para que podamos reproducir el error, aunque me da la sensación de que estás "disfrutando de los baches", así que no insisto ;).

noter:
aunque me da la sensación de que estás "disfrutando de los baches".

Bueno... esa no la entendí :confused:

Me deshice de la herencia de Print porque me está dando más dolores de cabeza que beneficios; y por esto es que no puedo confiar del todo en el compilador... era mentira que había resuelto el problema de las plantillas y la instancia en la declaración. La salida es la siguiente:

C:\Users\Usuario\AppData\Local\Temp\ccXYYSIO.ltrans0.ltrans.o: In function `Sd2Card::chipSelectHigh() [clone .constprop.49]':

ccXYYSIO.ltrans0.o:(.text+0x2ec): undefined reference to `SDRaw'

C:\Users\Usuario\AppData\Local\Temp\ccXYYSIO.ltrans0.ltrans.o: In function `Sd2Card::readEnd() [clone .constprop.47]':

ccXYYSIO.ltrans0.o:(.text+0x314): undefined reference to `SDRaw'

ccXYYSIO.ltrans0.o:(.text+0x31e): undefined reference to `SDRaw'

ccXYYSIO.ltrans0.o:(.text+0x322): undefined reference to `SDRaw'

ccXYYSIO.ltrans0.o:(.text+0x32c): undefined reference to `SDRaw'

C:\Users\Usuario\AppData\Local\Temp\ccXYYSIO.ltrans0.ltrans.o:ccXYYSIO.ltrans0.o:(.text+0x330): more undefined references to `SDRaw' follow

C:\Users\Usuario\AppData\Local\Temp\ccXYYSIO.ltrans0.ltrans.o: In function `main':

ccXYYSIO.ltrans0.o:(.text.startup+0x498): undefined reference to `unsigned int SdRawClass::put<float>(unsigned long, float const&)'

ccXYYSIO.ltrans0.o:(.text.startup+0x4b2): undefined reference to `SDRaw'

ccXYYSIO.ltrans0.o:(.text.startup+0x4b4): undefined reference to `SDRaw'

ccXYYSIO.ltrans0.o:(.text.startup+0x4b6): undefined reference to `unsigned int SdRawClass::get<float>(unsigned long, float const&)'

ccXYYSIO.ltrans0.o:(.text.startup+0x4e4): undefined reference to `SDRaw'

ccXYYSIO.ltrans0.o:(.text.startup+0x62c): undefined reference to `SDRaw'

ccXYYSIO.ltrans0.o:(.text.startup+0x630): undefined reference to `SDRaw'

ccXYYSIO.ltrans0.o:(.text.startup+0x634): undefined reference to `SDRaw'

ccXYYSIO.ltrans0.o:(.text.startup+0x638): undefined reference to `SDRaw'

C:\Users\Usuario\AppData\Local\Temp\ccXYYSIO.ltrans0.ltrans.o:ccXYYSIO.ltrans0.o:(.text.startup+0x63c): more undefined references to `SDRaw' follow

collect2.exe: error: ld returned 1 exit status

exit status 1
Error de compilación

En el adjunto está lo que tengo hasta el momento.

Gracias por cierto... :slight_smile:

readwritesector.zip (16.6 KB)

Perdona.
Como no habías vuelto a poner el código pensé que estabas en modo "autoaprendizaje" y que ibas disfrutando los avances por tí mismo (de ahí lo de disfrutar los baches).

Ahora que estoy viendo tu código actual ¿Has pensado en heredar directamente de Stream? Muchas de las funciones te servirán sin necesidad de redefinirlas.

noter:
Ahora que estoy viendo tu código actual ¿Has pensado en heredar directamente de Stream?

Lucario448:
En mi defensa, lo que no me gusta de Stream, es que las lecturas las hace con "timeout"; eso estaría bien pero cuando la longitud del "stream" es cambiante (ej.: el búfer de entrada del puerto serie). Pero para trabajar una tarjeta SD en forma "cruda", donde la capacidad (longitud del "stream") solo puede cambiar cambiando el medio físico... un "timeout" más bien entorpece el rendimiento del sistema.

De hecho, al principio tenía decidido simplemente heredar de Stream, pero por esa razón deseché la idea. ¿Seguro que un timeout no reduciría el rendimiento del programa?

Y sí, traté de resolver los problemas por cuenta propia; pero desde que el compilador me dio esa salida poco descriptiva, se me agotaron las ideas :frowning: