348 lines
10 KiB
C
348 lines
10 KiB
C
/* =========================================================================
|
|
* PROYECTO: Sistema de Registro y Telemetría para el Nanosatélite "Andrómeda-1"
|
|
* -------------------------------------------------------------------------
|
|
* CONTEXTO:
|
|
* La Agencia Espacial Experimental está desarrollando el software de a bordo
|
|
* para su próximo nanosatélite. El sistema necesita gestionar memoria de
|
|
* forma dinámica y eficiente debido a los recursos limitados del microcontrolador
|
|
* y a la naturaleza impredecible de las ráfagas de datos en órbita.
|
|
*
|
|
* OBJETIVO:
|
|
* Diseñar e implementar un programa en lenguaje C que resuelva los siguientes
|
|
* módulos de gestión de memoria dinámica requeridos por la estación de tierra:
|
|
*
|
|
* 1. Vector Dinámico Básico (Canales de Sensores):
|
|
* Pide al operador un número N de canales activos, utiliza malloc para
|
|
* reservar un arreglo de enteros con las lecturas iniciales, muéstralo en
|
|
* consola y libera correctamente la memoria con free al terminar.
|
|
*
|
|
* 2. Cadenas Dinámicas (Identificadores de Misión):
|
|
* Escribe una función que reciba una cadena estática (char *) con el nombre
|
|
* de código del satélite, calcule su longitud exacta, reserve espacio
|
|
* dinámicamente con malloc, copie la cadena y devuelva el nuevo puntero
|
|
* dinámico para ser registrado en los logs del sistema.
|
|
*
|
|
* 3. Estructura Dinámica (Buffer de Archivos de Telemetría):
|
|
* Define una struct Archivo que contenga dos campos: size_t tamano y
|
|
* uint8_t *datos. Escribe una función que reciba el tamaño deseado y reserve
|
|
* memoria dinámicamente tanto para la estructura en sí como para su búfer
|
|
* interno de datos binarios.
|
|
*
|
|
* 4. Redimensionamiento con realloc (Stream de Datos en Tiempo Real):
|
|
* Crea una rutina que lea números enteros (paquetes de telemetría) desde
|
|
* la consola de forma indefinida hasta una condición de parada. Almacénalos
|
|
* en un arreglo dinámico que duplique su tamaño cada vez que se llene
|
|
* utilizando realloc para optimizar el almacenamiento.
|
|
*
|
|
* 5. Estructuras Anidadas Dinámicas (Subsistemas del Satélite):
|
|
* Crea una estructura principal (por ejemplo, MisionEspacial) que contenga
|
|
* un puntero a un arreglo dinámico de subestructuras (representando varios
|
|
* subsistemas como energía, propulsión y comunicación). Asegúrate de
|
|
* implementar un protocolo estricto de liberación en orden inverso
|
|
* (primero las subestructuras internas y sus recursos, luego el arreglo
|
|
* principal) para evitar fugas de memoria (memory leaks) críticas en órbita.
|
|
*
|
|
* REQUISITOS TÉCNICOS:
|
|
* - Uso obligatorio de las funciones de <stdlib.h> (malloc, realloc, free).
|
|
* - Validación de punteros (verificar que no sean NULL tras cada reserva).
|
|
* - Código limpio, modularizado en funciones y bien comentado.
|
|
* ========================================================================= */
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
|
|
typedef struct{
|
|
size_t size;
|
|
uint8_t *datos;
|
|
}TelemetryFile;
|
|
|
|
typedef struct{
|
|
TelemetryFile base;
|
|
size_t offset;
|
|
}TelemetryArray;
|
|
|
|
typedef struct{
|
|
int n_chanels;
|
|
int* chanels;
|
|
TelemetryFile* telemetry_file;
|
|
TelemetryArray telemetry_array;
|
|
}ProgramData;
|
|
|
|
|
|
void print_menu(ProgramData *);
|
|
void print_data(ProgramData *);
|
|
void get_nchanels(ProgramData *);
|
|
void get_chanels(ProgramData *);
|
|
|
|
void get_telemetry_file(ProgramData *);
|
|
TelemetryFile* telemetry_file_create(size_t fs);
|
|
void telemetry_file_free(ProgramData *);
|
|
|
|
void get_telemetry_data(ProgramData *);
|
|
bool telemetry_array_is_full(ProgramData *);
|
|
void telemetry_array_alloc(ProgramData *);
|
|
void telemetry_array_free(ProgramData *);
|
|
void telemetry_array_set(ProgramData *, uint8_t data);
|
|
|
|
void free_data(ProgramData*);
|
|
void pause(void);
|
|
|
|
|
|
int main(void){
|
|
|
|
ProgramData data = {
|
|
.n_chanels = 0,
|
|
.chanels = NULL,
|
|
.telemetry_file = NULL,
|
|
.telemetry_array = {
|
|
.base = {
|
|
.size = 0,
|
|
.datos = NULL
|
|
},
|
|
.offset = 0
|
|
}
|
|
};
|
|
|
|
print_menu(&data);
|
|
|
|
free_data(&data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void print_menu(ProgramData* ref_data){
|
|
|
|
int option = 0;
|
|
int exit = 0;
|
|
|
|
system("clear");
|
|
printf("MENU DE OPCIONES\n");
|
|
printf("\t 1- Cargar canales\n");
|
|
printf("\t 2- Mostrar Datos\n");
|
|
printf("\t 3- Crear archivo de telemetría\n");
|
|
printf("\t 4- Recibir telemetria\n");
|
|
printf("\t 5- Salir\n");
|
|
|
|
scanf("%d", &option);
|
|
|
|
switch (option) {
|
|
case 1:
|
|
get_nchanels(ref_data);
|
|
get_chanels(ref_data);
|
|
break;
|
|
case 2:
|
|
print_data(ref_data);
|
|
break;
|
|
case 3:
|
|
get_telemetry_file(ref_data);
|
|
break;
|
|
case 4:
|
|
get_telemetry_data(ref_data);
|
|
break;
|
|
case 5:
|
|
exit = 1;
|
|
break;
|
|
}
|
|
|
|
if(!exit){
|
|
print_menu(ref_data);
|
|
}
|
|
|
|
}
|
|
|
|
void get_telemetry_data(ProgramData *ref_data){
|
|
system("clear");
|
|
printf("RECEPCION DE TELEMETRIA\n");
|
|
uint8_t read_data;
|
|
|
|
do{
|
|
printf("\nIngresar valor (0 para terminar):");
|
|
scanf("%" SCNu8, &read_data);
|
|
|
|
//printf("Se ha leido: %" SCNu8 "\n", read_data);
|
|
|
|
if(read_data > 0){
|
|
telemetry_array_set(ref_data, read_data);
|
|
}
|
|
|
|
}while(read_data > 0);
|
|
}
|
|
|
|
bool telemetry_array_is_full(ProgramData *ref_data){
|
|
|
|
uint8_t* start_add = ref_data->telemetry_array.base.datos;
|
|
|
|
if(start_add == NULL){
|
|
return true;
|
|
}
|
|
|
|
uint8_t* end_add = start_add + ref_data->telemetry_array.base.size;
|
|
uint8_t* test_add = start_add + ref_data->telemetry_array.offset;
|
|
return test_add >= (end_add);
|
|
}
|
|
|
|
void telemetry_array_alloc(ProgramData *ref_data){
|
|
//Si esta vacio reserva espacio para uno.
|
|
if(ref_data->telemetry_array.base.datos == NULL){
|
|
ref_data->telemetry_array.base.datos = malloc(sizeof(uint8_t));
|
|
if(ref_data->telemetry_array.base.datos == NULL){
|
|
perror("Error asignando memoria para streaming de telemetria.");
|
|
exit(1);
|
|
}
|
|
ref_data->telemetry_array.base.size = 1;
|
|
ref_data->telemetry_array.offset = 0;
|
|
return;
|
|
}
|
|
|
|
uint8_t* result = realloc(ref_data->telemetry_array.base.datos, ref_data->telemetry_array.base.size * 2);
|
|
|
|
if(result == NULL){
|
|
perror("Error reasignando memoria para streaming de telemetria.");
|
|
exit(1);
|
|
}
|
|
|
|
ref_data->telemetry_array.base.datos = result;
|
|
ref_data->telemetry_array.base.size *= 2;
|
|
|
|
printf("La nueva capacidad es: %zu \n", ref_data->telemetry_array.base.size);
|
|
}
|
|
|
|
void telemetry_array_free(ProgramData *ref_data){
|
|
if(ref_data->telemetry_array.base.datos == NULL){
|
|
free(ref_data->telemetry_array.base.datos);
|
|
ref_data->telemetry_array.base.datos = NULL;
|
|
}
|
|
}
|
|
|
|
void telemetry_array_set(ProgramData *ref_data, uint8_t data){
|
|
if(telemetry_array_is_full(ref_data)){
|
|
printf("Esta lleno, vamos a agrandar \n");
|
|
telemetry_array_alloc(ref_data);
|
|
}
|
|
|
|
*(ref_data->telemetry_array.base.datos + ref_data->telemetry_array.offset) = data;
|
|
ref_data->telemetry_array.offset += 1;
|
|
}
|
|
|
|
|
|
void get_telemetry_file(ProgramData *ref_data){
|
|
|
|
size_t fs;
|
|
|
|
system("clear");
|
|
|
|
printf("CREAR ARCHIVO DE TELEMETRIA\n");
|
|
printf("\tEnter de size in bytes:");
|
|
scanf("%zu", &fs);
|
|
|
|
telemetry_file_free(ref_data);
|
|
ref_data->telemetry_file = telemetry_file_create(fs);
|
|
|
|
}
|
|
|
|
void telemetry_file_free(ProgramData *ref_data){
|
|
if(ref_data->telemetry_file != NULL){
|
|
if(ref_data->telemetry_file->datos != NULL){
|
|
free(ref_data->telemetry_file->datos);
|
|
ref_data->telemetry_file->datos = NULL;
|
|
}
|
|
free(ref_data->telemetry_file);
|
|
ref_data->telemetry_file = NULL;
|
|
}
|
|
}
|
|
|
|
TelemetryFile* telemetry_file_create(size_t fs){
|
|
TelemetryFile* telemetry_file = malloc(sizeof(TelemetryFile));
|
|
|
|
if(telemetry_file == NULL){
|
|
perror("Error creating telemetry file.");
|
|
exit(1);
|
|
}
|
|
|
|
telemetry_file->size = fs;
|
|
telemetry_file->datos = malloc(sizeof(uint8_t)*fs);
|
|
|
|
if(telemetry_file->datos == NULL){
|
|
free(telemetry_file);
|
|
telemetry_file = NULL;
|
|
perror("Error allocating memory for the buffer to telemetry file.");
|
|
exit(1);
|
|
}
|
|
|
|
return telemetry_file;
|
|
|
|
}
|
|
|
|
void get_nchanels(ProgramData* ref_data){
|
|
system("clear");
|
|
int n_chanels = 0;
|
|
printf("Cantidad de canales: ");
|
|
scanf("%d", &n_chanels);
|
|
|
|
ref_data->n_chanels = n_chanels;
|
|
|
|
}
|
|
|
|
void get_chanels(ProgramData* ref_data){
|
|
if(ref_data->chanels != NULL){
|
|
free(ref_data->chanels);
|
|
ref_data->chanels = NULL;
|
|
}
|
|
ref_data->chanels = malloc(sizeof(int)*ref_data->n_chanels);
|
|
if(ref_data->chanels == NULL){
|
|
perror("No se pudo reservar memoria para los canales.");
|
|
exit(1);
|
|
}
|
|
for(int i=0; i < ref_data->n_chanels; i++){
|
|
int chanel;
|
|
printf("Frecuacia en Mhz del canal%d:", i);
|
|
scanf("%d", &chanel);
|
|
*(ref_data->chanels + i) = chanel;
|
|
}
|
|
}
|
|
|
|
void print_data(ProgramData* ref_data){
|
|
system("clear");
|
|
printf("DATOS DEL PROGRAMA\n");
|
|
printf("Cantidad de canales: %d\n", ref_data->n_chanels);
|
|
|
|
for (int i=0; i < ref_data->n_chanels; i++){
|
|
printf("\t CH %d Mhz\n", *(ref_data->chanels + i));
|
|
}
|
|
|
|
if(ref_data->telemetry_file != NULL){
|
|
printf("Archivo de telemetria creado. Size: %zu bytes.\n", ref_data->telemetry_file->size);
|
|
}
|
|
|
|
printf("Datos de telemetria: ");
|
|
for(size_t i=0; i < ref_data->telemetry_array.offset; i++){
|
|
printf("%" SCNu8 ", ", *(ref_data->telemetry_array.base.datos + i));
|
|
}
|
|
if(ref_data->telemetry_array.base.size == 0){
|
|
printf("No hay datos.");
|
|
}
|
|
printf("\n");
|
|
pause();
|
|
}
|
|
|
|
void free_data(ProgramData* ref_data){
|
|
if(ref_data->chanels){
|
|
free(ref_data->chanels);
|
|
}
|
|
telemetry_file_free(ref_data);
|
|
telemetry_array_free(ref_data);
|
|
}
|
|
|
|
void pause(void){
|
|
// 1. Limpiamos el búfer por si quedó algún caracter pendiente del scanf anterior
|
|
int c;
|
|
while ((c = getchar()) != '\n' && c != EOF);
|
|
// 2. Mostramos el mensaje y esperamos a que el usuario presione Enter de verdad
|
|
printf("Presione Enter para continuar...\n");
|
|
getchar();
|
|
}
|