Autor Tema: Desreferenciando caracteres en una struct...  (Leído 6449 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Desreferenciando caracteres en una struct...
« en: 07 de Febrero de 2016, 21:31:15 »
Estoy con una aplicacion de un dataloger por puerto serie usando un LPC11u67 (cortex M0+). Las librerías de NXP (LPCOpen) para esta familia posee una implementacion de un RingBuffer en la uart. La definicion del RingBuffer es la siguiente:

Código: C
  1. typedef struct {
  2.         void *data;
  3.         int count;
  4.         int itemSz;
  5.         uint32_t head;
  6.         uint32_t tail;
  7. } RINGBUFF_T;

como se ve data es un puntero a void, por que el dato almacenado en el ringbuffer puede ser de cualquier tipo.

esta es la funcion de inicialiacion del ringbuffer

Código: C
  1. /* Initialize ring buffer */
  2. int RingBuffer_Init(RINGBUFF_T *RingBuff, void *buffer, int itemSize, int count)
  3. {
  4.         RingBuff->data = buffer;
  5.         RingBuff->count = count;
  6.         RingBuff->itemSz = itemSize;
  7.         RingBuff->head = RingBuff->tail = 0;
  8.  
  9.         return 1;
  10. }

En mi programa tengo esto:

Código: C
  1. /* Transmit and receive ring buffers */
  2. STATIC RINGBUFF_T txring, rxring;
  3.  
  4. /* Ring buffer size */
  5. #define UART_RB_SIZE 1024
  6.  
  7. /* Transmit and receive buffers */
  8. static uint8_t rxbuff[UART_RB_SIZE];
  9. static uint8_t txbuff[UART_RB_SIZE];

Con esto creo 2 buffer circulares, el que me interesa es rxring.

La idea es que en la recepcion de cada caracter en la UART insertemos el caracter en buffer circular.
Entonces la ISR de la UART es así:

Código: C
  1. void USART1_4_IRQHandler(void)
  2. {
  3.         /* Want to handle any errors? Do it here. */
  4.  
  5.  
  6.         /* Use default ring buffer handler. Override this with your own
  7.            code if you need more capability. */
  8.         Chip_UARTN_IRQRBHandler(LPC_USART1, &rxring, &txring);
  9.  
  10.                 if(RingBuffer_GetCount(&rxring) == WR_BUFF_SIZE){
  11.                         isRBHalfFull = 1;
  12.                         RingBuffer_PopMult(&rxring, wr_buf, WR_BUFF_SIZE);
  13.                 }else{
  14.                         isRBHalfFull = 0;
  15.                 }
  16.  
  17. }

Acá esty haciendo algo que no devo, pero no es ese el problema. Como ven se llama a Chip_UARTN_IRQRBHandler y se le pasa como parámatro la uart y los las direcciones de los buffer circulares.
Esa IRQHandler hace lo siguiente:

Código: C
  1. /* UART receive/transmit interrupt handler for ring buffers */
  2. void Chip_UARTN_IRQRBHandler(LPC_USARTN_T *pUART, RINGBUFF_T *pRXRB, RINGBUFF_T *pTXRB)
  3. {
  4.         /* Handle transmit interrupt if enabled */
  5.         if ((Chip_UARTN_GetStatus(pUART) & UARTN_STAT_TXRDY) != 0) {
  6.                 Chip_UARTN_TXIntHandlerRB(pUART, pTXRB);
  7.  
  8.                 /* Disable transmit interrupt if the ring buffer is empty */
  9.                 if (RingBuffer_IsEmpty(pTXRB)) {
  10.                         Chip_UARTN_IntDisable(pUART, UARTN_INTEN_TXRDY);
  11.                 }
  12.         }
  13.  
  14.         /* Handle receive interrupt */
  15.         Chip_UARTN_RXIntHandlerRB(pUART, pRXRB);
  16. }

donde lo realmente importante es que se llama a    Chip_UARTN_RXIntHandlerRB(pUART, pRXRB);
Ese Handler es el que se encarga de poner el caracyer en el RB:

Código: C
  1. /* UART receive-only interrupt handler for ring buffers */
  2. void Chip_UARTN_RXIntHandlerRB(LPC_USARTN_T *pUART, RINGBUFF_T *pRB)
  3. {
  4.         /* New data will be ignored if data not popped in time */
  5.         while ((Chip_UARTN_GetStatus(pUART) & UARTN_STAT_RXRDY) != 0) {
  6.                 uint8_t ch = Chip_UARTN_ReadByte(pUART);
  7.                 RingBuffer_Insert(pRB, &ch);
  8.         }
  9. }

Por si a alguie le interesa la implementacion de RingBuffer_Insert es la siguiente:

Código: C
  1. /* Insert a single item into Ring Buffer */
  2. int RingBuffer_Insert(RINGBUFF_T *RingBuff, const void *data)
  3. {
  4.         uint8_t *ptr = RingBuff->data;
  5.  
  6.         /* We cannot insert when queue is full */
  7.         if (RingBuffer_IsFull(RingBuff))
  8.                 return 0;
  9.  
  10.         ptr += RB_INDH(RingBuff) * RingBuff->itemSz;
  11.         memcpy(ptr, data, RingBuff->itemSz);
  12.         RingBuff->head++;
  13.  
  14.         return 1;
  15. }

Bueno, espero ese proceso se entienda. Si yo envío una gran secuencia de datos a este dataloger, cada caracter recivido es ingresado al buffer circuilar.
Luego lo que yo estoy haciendo (y está mal donde lo hago) es esperar a tener WR_BUFF_SIZE (512 en este caso) en el RB, cuando esto sucede saco WR_BUFF_SIZE datos del RB y lospongo en un buffer de escritura para una sdCard....

Bueno, el tema es que esto funciona casi perfecto. Supongamos envío 1124 bytes. Se reciven 512 en el RB y cuando esto sucede se pone en 1 una bandera y se sacan esos bytes del RB y se los pone en otro buffer. Mientras seguimos reciviendo se escriben en la SD esos 512 bytes. Se reciven 512 bytes más y pasa lo mismo. pero luego se reciben los últimos 100 bytes y ahí me queda el problema, esos 100 bytes quedarán en el RB hasta que lleguen 412 bytes más y si estos no llegan quedarán atrapados ahí.

Entonces acá biene el tema que quiero hacer. Dentro de la ISR de la uart, despues de poner el dato en el RB me gustaría obtener dicho caracter para verificar y compararlo contra algún caracter de escape.
El problema es que no sé como desreferenciar el último caracter, partiendo de la estructura del RB que tengo...
Hay una funcion llamada RingBuffer_Pop la cual saca 1 dato del RB, pero lo que hace es realmente sacarlo, yo solo quiero leerlo:

Código: C
  1. /* Pop single item from Ring Buffer */
  2. int RingBuffer_Pop(RINGBUFF_T *RingBuff, void *data)
  3. {
  4.         uint8_t *ptr = RingBuff->data;
  5.  
  6.         /* We cannot pop when queue is empty */
  7.         if (RingBuffer_IsEmpty(RingBuff))
  8.                 return 0;
  9.  
  10.         ptr += RB_INDT(RingBuff) * RingBuff->itemSz;
  11.         memcpy(data, ptr, RingBuff->itemSz);
  12.         RingBuff->tail++;
  13.  
  14.         return 1;
  15. }

Hace uso de esta macro:
Código: C
  1. #define RB_INDH(rb)                ((rb)->head & ((rb)->count - 1))
  2. #define RB_INDT(rb)                ((rb)->tail & ((rb)->count - 1))

Podría tomar parte de ese código, pero el tema es que no lo entiendo y realmente me gustaría entender como funciona esa desreferencia...

Saludos y gracias!
« Última modificación: 08 de Febrero de 2016, 00:19:19 por elgarbe »
-
Leonardo Garberoglio

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Desreferenciando caracteres en una struc...
« Respuesta #1 en: 07 de Febrero de 2016, 22:48:35 »
Citar
Hay una funcion llamada RingBuffer_Pop la cual saca 1 dato del RB, pero lo que hace es realmente sacarlo, yo solo quiero leerlo:
Pero ademas lo que lo saca lo hace desde el tail

Y no es mejor leer siempre lo que llega ? o Pensas revisar cada tanto para ver si no llega mas nada y ahi verificar si esta el ultimo char indicando el final?
Y si llegan mas cosas y ese char que te indica el fin queda en el medio ?

Supongamos que la hiciste vos, y yo creo que estas intentado buscar una funcion que lea lo ultimo ingresado.

El ultimo valor esta dado por (head-1), por que se pre-incrementa al ingresar el dato apuntando a la direccion siguiente.
El tema es que es un void. Y habria que castearlo a un uint8_t.

Código: C
  1. static uint8_t RingBuffer_ReadByte( const RINGBUFF_T *RingBuff)
  2. {
  3.         uint8_t  ui8Temp;
  4.  
  5.         //
  6.         //  Reviso que el puntero no sea Nulo, es decir que todavia no se inicializo
  7.         //
  8.  
  9.         if(RingBuffer->data == NULL )
  10.         {
  11.                 DebugMsg("Usaste mal la funcion y no inicializaste el buffer");
  12.                 return 0;
  13.         }
  14.  
  15.         //
  16.         // Reviso que el buffer no este vacio, si esta vacio no deberia ser capas de leer nada
  17.         // Deberias asegurarte antes... esto es una comprobacion tardia
  18.         //
  19.  
  20.  
  21.         if(RingBuffer_GetCount(RingBuff)==0)
  22.         {
  23.                 DebugMsg("Estas tratando de leer algo vacio..");
  24.                 return 0;
  25.         }
  26.  
  27.  
  28.         //
  29.         // Necesito wrapear el puntero ? En caso que de toda la vuelta.
  30.         //
  31.  
  32.  
  33.         if(Ringbuff->head==0)
  34.         {
  35.                 // Buffer tiene algo, y head es 0, por lo tanto quiere decir que el buffer se paso
  36.                 // Y debo ver el ultimo valor.
  37.                 ui8Temp = ((uint8_t *)Ringbuff->data)[Ringbuff->StructSize];
  38.         }
  39.         else
  40.         {
  41.                 // Buffer posee algo y es posible usarlo, no se necesita preocuparse por el wrap
  42.                 // Ya que head no es 0
  43.                 ui8Temp = ((uint8_t *)Ringbuff->data)[(Ringbuff->head)-1];
  44.         }
  45.  
  46.  
  47.         return ui8Temp;
  48. }

Realmente no se si estoy haciendo algo malo o bueno pero es lo unico que se me ocurre en estos momentos. Y como que se vuelve un poquito jodido probarlo.

EDIT:

Cambie el codigo. Espero que funcione. El acceso a la estructura a traves de un pointer tiene la mas alta prioridad, luego como los [] tiene mayor orden de precedencia que el cast, debo ponerle otros parentesis ya que () y [] son asociativos de izquierda a derecha, primero se ejecuta el (). Y esa es la explicacion de como se llego a eso :P

EDIT2:
El codigo posee una proteccion de wrap, como no se de donde tomar el tamaño maximo del buffer ( que no sea el #define asi es mas general para cualquier array ) pense crear un StructSize. Aunque la estructura solo necesitaria: puntero al buffer, ReadIndex, WriteIndex, Size. Y con eso calculas todo, a no ser que quieras ahorrarte un poco de calculo y poner el Count, que seria un (WriteIndex - ReadIndex)

Y una cosa mas..
no entiendo como en tu

RingBuffer_Insert()

No wrapeas el indice ( head ), ya que lo unico que haces es incrementarlo. Pero no veo en ningun lado que se fije si llego al maximo y que lo lleve a 0 para comenzar por el otro lado. Como realmente un Ring Buffer haria. Si jamas lo vas a llenar y siempre terminas vaciandolo y borrando todo ( poniendo head/tail a 0 ) entonces no hace falta el codigo del wrap que puse. ni la comprobacion esa. Pero dejaria de ser un Ring Buffer como tal, y un buffer mas :P
« Última modificación: 08 de Febrero de 2016, 00:16:37 por KILLERJC »

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re:Desreferenciando caracteres en una struc...
« Respuesta #2 en: 08 de Febrero de 2016, 00:16:37 »
Y no posee una funciona esa libreria de buffer circular para tomar el ultimo valor?

no  :?

Y no es mejor leer siempre lo que llega ?

Lo que pasa es que este juego de librerías (las LPCOpen) ya traen todo para funcionar así con la UART y el ringbuffer. Si quiero recibir un caracter por la uart, verificar que es y luego meterlo al RB tendría que mirar un poco las funciones... es una opción válida y la voy a analizar. Por lo que vi esta todo medio pensado para usar el RB, pero seguro que de alguna forma me lo puedo saltear en la ISR de la uart.

o Pensas revisar cada tanto para ver si no llega mas nada y ahi verificar si esta el ultimo char indicando el final?

Tengo varias formas de hacerlo. Una forma es con un timer y una especie de timeout. Si no recivo nada por un tiempo, saco los datos que quedaron en el RB y los mando a la SD card y cierro el archivo. Acá no necesito leer el último caracter.


Y si llegan mas cosas y ese char que te indica el fin queda en el medio ?

Si implemento lo del caracter especial como escape (fin de datos) entonces es porque estoy bien seguro que lo que viene despues no sirve o es parte de otro archivo. Aún no me decido cual de las dos opciones tomar....

La aplicacion actual es como datalog de un controlador de vuelo de un UAV. Este está continuamente sacando la telemetría por un puerto serie. Entonces cuando terminas de volar la controladora sigue mandando datos que no son útiles... acá normalmente no hay que hacer nada. Apagar los equipos y listo, si quedaron datos en el RB no hay problema porque no sirven. Pero estoy tratando de pensarlo para que quede un poco más standar y reutilizable. Entonces, por ejemplo, hay un proyecto llamado openlog que al rezivir 3 CTRL+Z sale de modo log y pasa a modo comando y ahí podes  listar archivos, etc. La idea es incluir algo de eso...

Supongamos que la hiciste vos, y yo creo que estas intentado buscar una funcion que lea lo ultimo ingresado. Estoy intentando comprender como hacer, por que es bastante simple si es que es un pointer a uint8_t

El ultimo valor esta dado por (head-1), por que se pre-incrementa al ingresar el dato apuntando a la direccion siguiente. Para un ptr de 8 bits se me ocurre que deberia ser asi:

Código: C
  1. static uint8_t RingBuffer_ReadByte( const RINGBUFF_T *RingBuff)
  2. {
  3.      uint8_t  ui8Temp;
  4.  
  5.      // Revisar que exista el buffer (no NULL), revisar que NO este vacio aca. Y recien ahi proceder
  6.  
  7.      ui8Temp = Ringbuff->data[(Ringbuff->head)-1];
  8.  
  9.      return ui8Temp;
  10. }

El tema es que es un void. Y habria que castearlo a un uint8_t.

Código: C
  1. static uint8_t RingBuffer_ReadByte( const RINGBUFF_T *RingBuff)
  2. {
  3.      uint8_t  ui8Temp;
  4.  
  5.      // Revisar que exista el buffer (no NULL), revisar que NO este vacio aca.
  6.  
  7.      ui8Temp = ((uint8_t *)Ringbuff->data)[(Ringbuff->head)-1];
  8.  
  9.      return ui8Temp;
  10. }

Realmente no se si estoy haciendo algo malo o bueno pero es lo unico que se me ocurre en estos momentos. Y como que se vuelve un poquito jodido probarlo.

EDIT:

Cambie el codigo. Espero que funcione. El acceso a la estructura a traves de un pointer tiene la mas alta prioridad, luego como los [] tiene mayor orden de precedencia que el cast, debo ponerle otros parentesis ya que () y [] son asociativos de izquierda a derecha, primero se ejecuta el (). Y esa es la explicacion de como se llego a eso :P

Pobando....
-
Leonardo Garberoglio

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Desreferenciando caracteres en una struc...
« Respuesta #3 en: 08 de Febrero de 2016, 00:18:47 »
Te aviso que cambie el codigo hace rato :P. Lo edite xD bastante

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re:Desreferenciando caracteres en una struc...
« Respuesta #4 en: 08 de Febrero de 2016, 00:25:59 »
Y una cosa mas..
no entiendo como en tu

RingBuffer_Insert()

No wrapeas el indice ( head ), ya que lo unico que haces es incrementarlo. Pero no veo en ningun lado que se fije si llego al maximo y que lo lleve a 0 para comenzar por el otro lado. Como realmente un Ring Buffer haria. Si jamas lo vas a llenar y siempre terminas vaciandolo y borrando todo ( poniendo head/tail a 0 ) entonces no hace falta el codigo del wrap que puse. ni la comprobacion esa. Pero dejaria de ser un Ring Buffer como tal, y un buffer mas :P

No es mío, es de NXP  :P
Por lo que vi van incrementando el head y el tail siempre y la cantidad de datos actuales sale como la diferencia * size. He leido que es una forma más de trabajar con los RB:
http://www.simplyembedded.org/tutorials/interrupt-free-ring-buffer/

-
Leonardo Garberoglio

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Desreferenciando caracteres en una struc...
« Respuesta #5 en: 08 de Febrero de 2016, 04:07:13 »
No es mío, es de NXP  :P
Por lo que vi van incrementando el head y el tail siempre y la cantidad de datos actuales sale como la diferencia * size. He leido que es una forma más de trabajar con los RB:
http://www.simplyembedded.org/tutorials/interrupt-free-ring-buffer/

Interesante es la primera ves que lo veo implementado asi, muy buena esa.. Asi que para poder leerlo deberia ser asi (sin necesidad de wrappers):

Código: C
  1. ui8Temp = ((uint8_t *)Ringbuff->data)[((Ringbuff->head)-1) & (RingBuff->count - 1)];

De esa forma se resta 1 al head indicando la posicion anterior, y luego se hace la AND con el count-1. Asi formatearlo a lo que seria el indice.

Todo esto suponiendo que:

- count, sea la cantidad de lugares ( UART_RB_SIZE ) de la estructura, es decir lo inicializaste de esta forma:

RingBuffer_Init(&rxring, rxbuff, 1, UART_RB_SIZE);

Y una cosa que no esta dicho ahi, y que la libreria esa no verifica (y el articulo si) es que debe ser multiplo de 2 ( 128, 256, etc), y no puede ser un valor arbitrario que con el otro metodo si. Por que de ser un valor arbitrario count -1 no quedarian todos los bits que importan en 1 y asi "filtrar" el indice.

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re:Desreferenciando caracteres en una struc...
« Respuesta #6 en: 08 de Febrero de 2016, 10:19:20 »


Código: C
  1. ui8Temp = ((uint8_t *)Ringbuff->data)[((Ringbuff->head)-1) & (RingBuff->count - 1)];

De esa forma se resta 1 al head indicando la posicion anterior, y luego se hace la AND con el count-1. Asi formatearlo a lo que seria el indice.

Excelente, ahí obtuve el último caracter con ese código!
En mis pruebas le estaba errando en el casteo a uint8_t *. yo ponía (uint8_t *)(Ringbuff->data)[....].... no termino de entender como funcionan los paréntesis en cada caso...

Saludos!
-
Leonardo Garberoglio

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re:Desreferenciando caracteres en una struct...
« Respuesta #7 en: 08 de Febrero de 2016, 13:28:24 »
He tenido que cambiar los -> por .
no sé x q al compilador dejó de gustarle el -> y quiere . y no tengo tiepo de investigarlo  :D

Quedó funcionando así:

Código: C
  1. void USART1_4_IRQHandler(void)
  2. {
  3.         uint8_t key;
  4.         uint16_t lastpos;
  5.         /* Want to handle any errors? Do it here. */
  6.         /* Use default ring buffer handler. Override this with your own
  7.            code if you need more capability. */
  8.         Chip_UARTN_IRQRBHandler(LPC_USART1, &rxring, &txring);
  9.  
  10.         lastpos = ((rxring.head)-1) & (rxring.count - 1);
  11.         key = ((uint8_t *)rxring.data)[lastpos];
  12.         if(key == 27)
  13.         {
  14.                 isRBHalfFull = 2;
  15.         }else
  16.         {
  17.                 if(RingBuffer_GetCount(&rxring) == WR_BUFF_SIZE){
  18.                         isRBHalfFull = 1;
  19. //                      RingBuffer_PopMult(&rxring, wr_buf, WR_BUFF_SIZE);
  20.                 }else
  21.                 {
  22.                         isRBHalfFull = 0;
  23.                 }
  24.         }
  25. }

ese "lastpos" lo uso para debug, despues lo voy a sacar.
Entonces simplemete veo si el último caracter es el 27 (tecla escape) pongo la bandera en 2. Si reciví WR_BUFF_SIZE (tengo que cambiar algunos nombres agregando SD como prefijo para que se entienda que son de la sd) pongo la bandera en 1. El else que pone la bandera en 0 creo que lo puedo sacar sin problemas.

En el main tengo:

Código: C
  1. // Monto la SD card
  2.         fs_mount();
  3.         // Abro el archivo de logueo y veo el contenido de la primer línea
  4.         fs_ReadLog();
  5.         // Creo el archivo para loguear
  6.         fs_OpenFileWrite();
  7.  
  8.         while(1)
  9.         {
  10.                 while(!isRBHalfFull);   // Me quedo esperando a que la bandera sea distinta de 0
  11.  
  12.                 fs_WriteFile(isRBHalfFull);
  13.                 isRBHalfFull = 0;
  14. //              if(isRBHalfFull==1)
  15. //              {
  16. //                      // La bandera es 1, significa que tengo el buffer tiene WR_BUFF_SIZE bytes en él
  17. //                      // Los escrivo en la sd Card
  18. //                      fs_WriteFile(1);
  19. //                      // Reseteo bandera
  20. //                      isRBHalfFull = 0;
  21. //              }else if (isRBHalfFull==2)
  22. //              {
  23. //                      // La bandera está en 2, significa que se ha encontrado el caracter ESC (27)
  24. //                      // Los escrivo en la sd Card
  25. //                      fs_WriteFile(2);
  26. //                      // Reseteo bandera
  27. //                      isRBHalfFull = 0;
  28. //              }
  29.         }

y finalmente la función de escritura:

Código: C
  1. FRESULT fs_WriteFile(uint8_t f_TipoEscritura)
  2. {
  3.         FRESULT rc;                             // Result code
  4.         UINT bw;                                // bytes escritos
  5.         uint16_t count;
  6.  
  7.  
  8.         if(f_TipoEscritura == 1)
  9.         {
  10.                 count = WR_BUFF_SIZE;
  11.  
  12.         }else if(f_TipoEscritura == 2)
  13.         {
  14.                 // Tengo que obtener los bytes que quedaron en el buffer y escribirlos en el archivo
  15.                 count = RingBuffer_GetCount(&rxring);
  16.         }
  17.  
  18.         // Extraigo count bytes y los pongo en wr_buf
  19.         RingBuffer_PopMult(&rxring, wr_buf, count);
  20.  
  21. //      printf("Write a data\n");
  22.  
  23. //      systick_start;
  24.         // Intento escribir los datos que hay en wr_buf. bw guarda la cantidad de bytes escritos
  25.         rc = f_write(&Fil, wr_buf, count, &bw);
  26. //      systick_stop;
  27.         // En este array guardo los tiempos de escritura de cada llamado
  28. //      wrotes[idx++]=time;
  29.         // Verifico que se hallan escrito tantos bytes como WR_BUFF_SIZE.
  30.         // No sé si es muy útil esta verificacion. Quizás sirva para detectar la última escritura
  31.         // que puede no ser de WR_BUFF_SIZE bytes y cerrar el archivo. Pero si es justo de WR_BUFF_SIZE bytes?
  32.         if(bw == WR_BUFF_SIZE)
  33.         {
  34.                 // Me aseguro de que se almacene en la SD todos los datos.
  35.                 rc = f_sync(&Fil);
  36. //              printf("%d bytes escritos\n", bw);
  37.                 return rc;
  38.         }else
  39.         {
  40.                 // escribí menos bytes que WR_BUFF_SIZE. Deve ser que son los ultimos bytes que había en el RB
  41.                 rc = f_close(&Fil);
  42.                 return 0;
  43.         }
  44. }

Bien, eso está funcionando de 10. Abro un terminal, me conecto al puerto serie, le arrojo un archivo de texto en la terminal y del otro lado se graba en la sd card. Cuando se termina de transmitir apreto ESC y con eso grabo los ultimos bytes.

Bien, ahora me aparece un nuevo problema... pierdo todos los <LF> (Cuando está presedido de un CR) del archivo original  :P


* LF.jpg
(139.12 kB, 603x451 - visto 397 veces)


Le desconfío al encoding del FatFS... Voy a investigar un poco...

Saludos y gracias KILLER.
-
Leonardo Garberoglio

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Desreferenciando caracteres en una struct...
« Respuesta #8 en: 08 de Febrero de 2016, 14:03:08 »
Extraño que pierdas los LF.. Es raro por que es un valor comun como cualquiera :P.

Yo estuve tratando de hacer la funcion para que pueda ser usada con cualquier valor, ya que la libreria acepta un void, uno puede esperar valores float,byte,int, long, double , etc.
Y me quedaron 2 codigos que realmente no logro comprender demasiado del memcpy y es lo que pienso que esta mal, para mi memcpy deberia copiar 1 por 1 los elementos, hago la aritmetica en 8 bits  e itmSz. Pero luego no me queda claro si es que por ejemplo 4 elementos de un uin32_t pueden terminar en retorno todos juntos, y no espera que retorno sea un "array". Todavia no encontre nada respecto a eso.. asi que estoy buscando

Código: C
  1. static uint8_t RingBufferPeekLast( const RINGBUFF_T *RingBuff, void *retorno)
  2. {
  3.         uint32_t  ui32Offset
  4.         ui32Offset = ((RingBuff->head - 1) & (RingBuff->count - 1)) * RingBuff->itmSz;
  5.         memcpy(retorno,&(((uint8_t *)RingBuff->buff)[offset]),RingBuff->itmSz);
  6. }

Usando el codigo de lectura que pasaste (Igual un ptr a un uint8_t, como en la lectura, pero que no se si funcionara para otros tipos.):

Código: C
  1. static uint8_t RingBufferPeekLast( const RINGBUFF_T *RingBuff, void *retorno)
  2. {
  3.         uint8_t  *ptr = RingBuff->buff;
  4.         ptr += (RB_INDH(RingBuff)-1) * RingBuff->itmSz;
  5.         memcpy(retorno,ptr,RingBuff->itmSz);
  6. }

EDIT:

Citar
no sé x q al compilador dejó de gustarle el -> y quiere . y no tengo tiepo de investigarlo

Si te referis a esto:

key = ((uint8_t *)rxring.data)[lastpos];

es obvio el por que. ya que normalmente en las funciones que estuvimos haciendo arriba era un puntero a la estructura: RINGBUFF_T *RingBuff

Mientras que aca estas accediendo a la estructura. Y un elemento de la misma es data, Para poner un ejemplo:

RINGBUFF_T *RingBuff = &rxring;
key = ((uint8_t *)RingBuff->data)[lastpos];

Citar
Le desconfío al encoding del FatFS... Voy a investigar un poco...

Es raro por que no se preocupa por eso. Por que se complicaria la vida con eso? Directamente manda todos los bytes en fila... Lo unico que deberia preocuparse es por el '\0' en una string.


Y una ultima cosa que me esta carcomiendo la cabeza.
Imagino que esto es todo sin optimizaciones activas, ya que veo que no hay ningun "volatile" dando vueltas, especialmente en el buffer de lectura/escritura
« Última modificación: 08 de Febrero de 2016, 14:33:07 por KILLERJC »

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re:Desreferenciando caracteres en una struct...
« Respuesta #9 en: 08 de Febrero de 2016, 14:37:06 »
Recién estaba en el baño y me llegó un toque de inspiración. Tal ves el programa terminal este cambiando cr+lf por sólo lf... Ahora salí unas horas, dsp lo investigo
-
Leonardo Garberoglio

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re:Desreferenciando caracteres en una struct...
« Respuesta #10 en: 08 de Febrero de 2016, 18:21:28 »
Citar
no sé x q al compilador dejó de gustarle el -> y quiere . y no tengo tiepo de investigarlo

Si te referis a esto:

key = ((uint8_t *)rxring.data)[lastpos];

es obvio el por que. ya que normalmente en las funciones que estuvimos haciendo arriba era un puntero a la estructura: RINGBUFF_T *RingBuff

Mientras que aca estas accediendo a la estructura. Y un elemento de la misma es data, Para poner un ejemplo:

RINGBUFF_T *RingBuff = &rxring;
key = ((uint8_t *)RingBuff->data)[lastpos];

jaja, tenes razón!!!

Citar
Le desconfío al encoding del FatFS... Voy a investigar un poco...

Es raro por que no se preocupa por eso. Por que se complicaria la vida con eso? Directamente manda todos los bytes en fila... Lo unico que deberia preocuparse es por el '\0' en una string.

Si, no era por el encoding. Era por el terminal que enviaba el final de línea con un CR. Ahí lo configure para que envíe CR+LF y consigo exactamente el mismo archivo en la sd card. En realidad tiene 1 byte más porque no he sacado aún el último caracter (el ESC) del buffer antes de grabarlo.

* Captura de pantalla 2016-02-08 18.18.20.png
(56.62 kB, 735x357 - visto 370 veces)


Y una ultima cosa que me esta carcomiendo la cabeza.
Imagino que esto es todo sin optimizaciones activas, ya que veo que no hay ningun "volatile" dando vueltas, especialmente en el buffer de lectura/escritura

Si, no he habilitado las optimizaciones y no he verificado los VOLATILES. Ahora que está funcionando voy a ir retocando esas cosas.
Las optimizaciones nunca las uso... será cuestion de empezar a usarlas... o no...

Saludos y gracias!
-
Leonardo Garberoglio

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Desreferenciando caracteres en una struct...
« Respuesta #11 en: 08 de Febrero de 2016, 18:34:43 »
Citar
Si, no he habilitado las optimizaciones y no he verificado los VOLATILES. Ahora que está funcionando voy a ir retocando esas cosas.
Las optimizaciones nunca las uso... será cuestion de empezar a usarlas... o no...

No se que decirte.. algunos nunca usan, por ahi lei que es una mala costumbre ya que permite el mal "codeo" de la aplicacion, no usando las cosas como deben ser. Pero lo mas apreciable es la reduccion de lo ocupado en la flash y la velocidad. Que algunos por internet aseguran que han llegado al 40% de reduccion optimizando por velocidad ( que es lo que siempre se deberia hacer y no por espacio).. Ya que la flash no es algo demasiado restringente.

En fin cuestiones de gusto, solo lo vi y lo dije..

Respecto a :

Excelente, ahí obtuve el último caracter con ese código!
En mis pruebas le estaba errando en el casteo a uint8_t *. yo ponía (uint8_t *)(Ringbuff->data)[....].... no termino de entender como funcionan los paréntesis en cada caso...

Lo explique en el primer post:

Citar
Cambie el codigo. Espero que funcione. El acceso a la estructura a traves de un pointer tiene la mas alta prioridad ( -> ), luego como los [] tiene mayor orden de precedencia que el cast, debo ponerle otros parentesis ya que () y [] son asociativos de izquierda a derecha, primero se ejecuta el (). Y esa es la explicacion de como se llego a eso :P

http://en.cppreference.com/w/c/language/operator_precedence

Y algo mas grafico:
http://www.c4learn.com/c-programming/c-reading-complex-pointer-expression/

Pero por si acaso lo que estabas haciendo es
(uint8_t *)(Ringbuff->data)[....]

Prioridades 1ero lo de ( Ringbuff->data) , luego [], finalmente el cast. Es decir esos parentesis simplemente estaban de mas. No cumplian ninguna funcion. y el cast actuaba sobre el elemento devuelto.
« Última modificación: 08 de Febrero de 2016, 18:50:00 por KILLERJC »

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re:Desreferenciando caracteres en una struct...
« Respuesta #12 en: 08 de Febrero de 2016, 21:52:49 »
Y una ultima cosa que me esta carcomiendo la cabeza.
Imagino que esto es todo sin optimizaciones activas, ya que veo que no hay ningun "volatile" dando vueltas, especialmente en el buffer de lectura/escritura

acabo de poner volatile a esto:

Código: C
  1. static volatile RINGBUFF_T txring, rxring;

ya que esas estructuras se pueden modificar en la interrupcion.
El compilador me arroja unos cuantos warning sobre esto:

Código: C
  1. warning: passing argument 1 of 'RingBuffer_Init' discards 'volatile' qualifier from pointer target type
  2.   RingBuffer_Init(&rxring, rxbuff, 1, UART_RB_SIZE);

sabes a que se debe y si tengo que darle importancia?

Saludos
-
Leonardo Garberoglio

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re:Desreferenciando caracteres en una struct...
« Respuesta #13 en: 09 de Febrero de 2016, 02:00:02 »
Llegué tarde a la charla, pero creo poder responderte esto último.

Lo que te está diciendo es precisamente lo que va a suceder: que dentro de la función RingBuffer_init(...), actualmente, el primer argumento (&rxring) no va a ser tratado como volatile, y tal vez deberías revisarlo si querés que sea volatile también dentro de la función.

La solución es agregar también el modificador volatile al primer parámetro en la declaración de la función RingBuffer_Init(...).

P.D. En mis implementaciones de ring buffers, siempre usé ese método de calcular el tamaño por diferencia entre las posiciones iniciales y finales de la cola, pero tiene un problema si no se agregan controles adicionales: cuando el buffer se llena, la posición final iguala a la inicial y por ende podemos creer que el buffer está vacío cuando en realidad está lleno...
« Última modificación: 09 de Febrero de 2016, 02:04:57 por BrunoF »
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Desreferenciando caracteres en una struct...
« Respuesta #14 en: 09 de Febrero de 2016, 05:38:32 »
Exacto. si vas por usar volatile, los punteros tambien tienen que ser declarados como punteros A volatiles.

volatile type *ptr

P.D. En mis implementaciones de ring buffers, siempre usé ese método de calcular el tamaño por diferencia entre las posiciones iniciales y finales de la cola, pero tiene un problema si no se agregan controles adicionales: cuando el buffer se llena, la posición final iguala a la inicial y por ende podemos creer que el buffer está vacío cuando en realidad está lleno...

Si y yo siempre lo habia visto asi al RingBuffer, la verdad es que es la primera ves que lo veo implemetando de esta forma. La diferencia es que de la forma que decis el tamaño del buffer no esta limitado por nada, mientras que la forma que posee elgarbe si o si obliga a ser multiplo de 2. Creo que es la unica diferencia que note ( ademas de la estructura que posee variables mas.
« Última modificación: 09 de Febrero de 2016, 05:46:53 por KILLERJC »