# PDI: Ejercicio de evaluación PL1 ## Una posible solución de los ejercicios de la prueba de evaluación ## Gestión de la UART ![](https://i.imgur.com/PYYdKrB.png) Se dispone de un sistema conectado a otro ordenador externo mediante una UART que se comunican mediante el intercambio de TC/TM: * El último campo de la cabecera (Packet Length) contiene la cantidad de octetos – 1 que faltan por recibir después de la cabecera. Por ejemplo, si la cabecera es ```0x1B 0x2C 0xC0 0x01 0x00 0x05```, el último campo vale 5, esto significa que faltan por recibir 6 octetos. Para la gestión de esta comunicación ya se dispone del siguiente programa principal que funciona mediante sondeo de la UART. Una vez recibido el TC invoca la función ```procesa_y_respondeTC()``` que no hay que codificar. Asuma que ya están incluidos todos los ```include``` necesarios. NO se contempla el tratamiento de errores. Se garatiza que no se recibe más TCs hasta haber procesado el anterior. Se pide: * Convierta el código siguiente en una versión donde la gestión de recepción de la UART se haga mediante interrupciones, con arquitectura Top/Bottom y de forma que se realice la misma gestión de la trama. Defina las nuevas variables que estime oportunas y elimine las que no crea necesarias. ```c= uint16_t deserialize_uint16( uint8_t *p ) { /* NO HAY QUE HACERLA*/ } void procesa_y_respondeTC() { /* Procesa el TC y contesta con la TM: NO HAY QUE HACERLA */} #define MAX_PKT_SIZE 64 #define TC_HEADER_SIZE 6 uint32_t idx; int32_t rec; uint8_t tc_packet[MAX_PKT_SIZE]; uint16_t tam_packet; int main() { // TX/RX enable riscv_uart_enable_TX(); riscv_uart_enable_RX(); while (1) { idx = 0; do { // Recibo la cabecera del TC do { rec = riscv_getchar(); } while( rec == -1 ); tc_packet[ idx ] = (uint8_t)rec; idx++; } while (idx != TC_HEADER_SIZE); // Ya tengo la cabecera, obtengo el tamaño // solo miro el último octeto recibido tam_packet = deserialize_uint16( &tc_packet[4] ) + 1; do { do { rec = riscv_getchar(); } while ( rec == -1) ; // Espera la llegada del siguiente octeto // Y lo guarda tc_packet[idx] = (uint8_t)rec; idx++; } while (idx != (TC_HEADER_SIZE + tam_packet)); // proceso el TC y respondo con la TM procesa_y_respondeTC( tc_packet ); } // while return 0; } ``` :::spoiler ```c= void procesa_y_respondeTC( uint8_t buffer[] ) { /* Procesa el TC y contesta con la TM: NO HAY QUE HACERLA */} #define MAX_PKT_SIZE 64 #define TC_HEADER_SIZE 6 uint32_t idx; int32_t rec; uint8_t tc_packet[MAX_PKT_SIZE]; uint32_t tam_packet; // Nuevas variables uint8_t flag = 0; uint8_t cabecera = 1; void uart_irq( void ) { rec = riscv_getchar(); if ( cabecera != 0 ) { tc_packet[idx] = (uint8_t)rec; idx++; if ( idx == TC_HEADER_SIZE ) { tam_packet = deserialize_uint16( &tc_packet[4]) + 1; cabecera = 0; } // if } else { buffer[idx] = (uint8_t)rec; idx++; if ( idx == (TC_HEADER_SIZE + tam_packet) ) { flag = 1; idx = 0; cabecera = 1; } // if } // if } // ISR uint32_t main() { riscv_enable_tx(); riscv_enable_rx(); // Configuración de la IRQ install_irq_handler( UART_IRQ, uart_rx_irq_handler ); // Install uart handler riscv_uart_enable_RI(); // Enable RX irq plic_irq_unmask( UART_IRQ ); // PLIC UART irq unmask enable_ext_irq(); // Enable MIE.MEI enable_irq(); while( 1 ) { if ( flag != 0 ) { // Procesar el TC procesa_y_respondeTC( tc_packet ) // Actualizo el flag flag = 0; } } // while(1) } ``` ::: ## Gestión del tiempo de recepción del TC Se desea usar un temporizador con un resolución de decimas de segundo para evitar el bloqueo del programa en el caso de que no se reciba un TC completo. Este temporizador comenzará la cuenta al recibir el primer octeto del TC y tendrá un timeout de 2 segundos. Si transcurrido este tiempo no se ha recibido el TC completo, se resetea la recepción y se esperará un TC nuevo. Se pide: * Añadir al código realizado en el punto anterior la gestión del tiempo pedida. :::spoiler ```c= // Se añade la variable global contador uint32_t contador = 0; //--------------------- // Hay que añadir la ISR del timer void timer_handler( void ) { if ( contador != 0 ) { contador--; if ( contador == 0 ) { // Reset de las variables de control del TC idx = 0; cabecera = 1; } } } //--------------------- void uart_irq( void ) { rec = riscv_getchar(); if ( cabecera != 0 ) { // Se añade el control del comienzo del TC y puesta en marcha del contador if ( idx ==0 ) // comienzo del TC { // La frecuencia de la ISR es de 10Hz y hay que esperar máximo dos segundos contador = 20; } //---------------------- tc_packet[idx] = (uint8_t)rec; idx++; if ( idx == TC_HEADER_SIZE ) { tam_packet = deserialize_uint16( &tc_packet[4]) + 1; cabecera = 0; } // if } else { buffer[idx] = (uint8_t)rec; idx++; if ( idx == (TC_HEADER_SIZE + tam_packet) ) { flag = 1; idx = 0; cabecera = 1; // Se pone a cero el contador para evitar la cuenta del ISR del timer contador = 0; //-------------------- } // if } // if } // ISR // En la función main hay que añadir la configuración del timer printf("----------TIMER IRQ---------\n"); install_local_timer_handler( timer_handler ); // CLINT timer clock is 10Mhz local_timer_set_gap( 1000000 ); // La frecuencia de la ISR será de 10Hz //--------------------- ``` :::