/* ========================================================================= * 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 (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 #include #include #include #include #include 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(); }