# PDI: Ejercicio de evaluación PL1
## Una posible solución de los ejercicios de la prueba de evaluación
## Gestión de la UART

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
//---------------------
```
:::