/*
* Author: Iván Iglesias
* Date: 23-11-2026
* Description: PR2 - The goal of this exercise is to replace the parallel vector implementation
* with a design based on hierarchical data structures (tuples)
* and to break the code down into actions and functions.
*/
/* ------------------------------- */
/* System header files */
#include <stdio.h>
#include <stdbool.h>
/* Symbolic constants */
#define SENSORS_PER_WAGON 14
#define SENSORS_PER_AXLE 7
#define CRITICAL_TEMPERATURE 90.0
#define VIBRATION_ALERT_LEVEL 7.1
#define WEAR_CRITICAL_THRESHOLD 25.0
#define MIN_WORN_FOR_WARNING 3
#define COMPONENT_TYPES 4
#define MAX_FILENAME 101
/* Definition of types */
typedef enum
{
BEARING = 1,
WHEEL,
BRAKE,
AXLE
} tComponentType;
typedef struct
{
tComponentType componentType;
float temperature;
float vibration;
float residualLife;
} tSensor;
typedef tSensor tWagonSensors[SENSORS_PER_WAGON];
typedef int tAlertCounts[COMPONENT_TYPES];
typedef struct
{
float avgTemp;
float maxTemp;
int peakPos;
int alertCount;
int wornCount;
tAlertCounts alertCounts;
} tInspectionResult;
/* Function and action declarations */
/* Exercise 1 */
void loadWagonFromFile(char filename[], tWagonSensors sensors, bool *isRead);
/* Exercise 2 */
void inspectWagon(tWagonSensors sensors, tInspectionResult *result);
/* Exercise 2.1 */
bool isSensorWorn(tSensor sensor);
/* Exercise 2.2 */
bool isSensorInAlert(tSensor sensor);
/* Exercise 2.3 */
int getComponentTypeIndex(tComponentType compType);
/* Exercise 3 */
void displaySummary(tWagonSensors sensors, tInspectionResult result);
/* Exercise 3.1 */
char *getSensorAxleName(int position);
/* Exercise 3.2 */
char *getComponentName(tComponentType compType);
/* Main function */
int main(void)
{
tWagonSensors sensors;
char filename[MAX_FILENAME];
tInspectionResult inspectionResult;
bool isRead;
printf("--- WAGON INSPECTION SYSTEM (PR2 - MODULAR) ---\n");
printf("LOAD DATA FROM FILE. ENTER FILE NAME >> ");
if (scanf("%100s", filename) != 1)
{
printf("Error: Could not open file\n");
return 1;
}
loadWagonFromFile(filename, sensors, &isRead);
if (isRead)
{
inspectWagon(sensors, &inspectionResult);
displaySummary(sensors, inspectionResult);
}
else
{
printf("Error: Could not open file\n");
}
return 0;
}
/* Exercise 1 */
void loadWagonFromFile(char filename[], tWagonSensors sensors, bool *isRead)
{
FILE *fileToRead;
int i;
int componentTypeValue;
*isRead = false;
fileToRead = fopen(filename, "r");
if (fileToRead == NULL)
{
return;
}
for (i = 0; i < SENSORS_PER_WAGON; i++)
{
if (fscanf(fileToRead, "%d %f %f %f",
&componentTypeValue,
&sensors[i].temperature,
&sensors[i].vibration,
&sensors[i].residualLife) != 4)
{
fclose(fileToRead);
return;
}
if (componentTypeValue < BEARING || componentTypeValue > AXLE)
{
fclose(fileToRead);
return;
}
sensors[i].componentType = (tComponentType) componentTypeValue;
}
fclose(fileToRead);
*isRead = true;
}
/* Exercise 2 */
void inspectWagon(tWagonSensors sensors, tInspectionResult *result)
{
int i;
int componentIndex;
float sumTemperature;
sumTemperature = 0.0f;
result->maxTemp = sensors[0].temperature;
result->peakPos = 1;
result->alertCount = 0;
result->wornCount = 0;
for (i = 0; i < COMPONENT_TYPES; i++)
{
result->alertCounts[i] = 0;
}
for (i = 0; i < SENSORS_PER_WAGON; i++)
{
sumTemperature += sensors[i].temperature;
if (sensors[i].temperature > result->maxTemp)
{
result->maxTemp = sensors[i].temperature;
result->peakPos = i + 1;
}
if (isSensorWorn(sensors[i]))
{
result->wornCount++;
}
if (isSensorInAlert(sensors[i]))
{
result->alertCount++;
componentIndex =
getComponentTypeIndex(sensors[i].componentType);
result->alertCounts[componentIndex - 1]++;
}
}
result->avgTemp = sumTemperature / SENSORS_PER_WAGON;
}
/* Exercise 2.1 */
bool isSensorWorn(tSensor sensor)
{
return sensor.residualLife < WEAR_CRITICAL_THRESHOLD;
}
/* Exercise 2.2 */
bool isSensorInAlert(tSensor sensor)
{
return sensor.temperature > CRITICAL_TEMPERATURE ||
sensor.vibration > VIBRATION_ALERT_LEVEL ||
isSensorWorn(sensor);
}
/* Exercise 2.3 */
int getComponentTypeIndex(tComponentType compType)
{
int index;
switch (compType)
{
case BEARING:
index = 1;
break;
case WHEEL:
index = 2;
break;
case BRAKE:
index = 3;
break;
case AXLE:
index = 4;
break;
default:
index = 0;
break;
}
return index;
}
/* Exercise 3 */
void displaySummary(tWagonSensors sensors, tInspectionResult result)
{
int i;
printf("----------------------------------------\n");
printf("INSPECTION SUMMARY\n");
printf("----------------------------------------\n");
printf("COMPONENT TYPES: 1-BEARING, 2-WHEEL, 3-BRAKE, 4-AXLE\n");
printf("AVERAGE TEMPERATURE (CELSIUS): %.2f\n",
result.avgTemp);
printf("PEAK TEMPERATURE (CELSIUS): %.2f AT POSITION %d "
"(AXLE: %s, TYPE: %s)\n",
result.maxTemp,
result.peakPos,
getSensorAxleName(result.peakPos),
getComponentName(sensors[result.peakPos - 1].componentType));
if (result.alertCount > 0)
{
printf("COMPONENTS IN ALERT: %d\n", result.alertCount);
for (i = 0; i < SENSORS_PER_WAGON; i++)
{
if (isSensorInAlert(sensors[i]))
{
printf("POSITION %d - TYPE: %s\n",
i + 1,
getComponentName(sensors[i].componentType));
}
}
printf("ALERTS BY COMPONENT TYPE:\n");
printf("- BEARING: %d\n",
result.alertCounts[getComponentTypeIndex(BEARING) - 1]);
printf("- WHEEL: %d\n",
result.alertCounts[getComponentTypeIndex(WHEEL) - 1]);
printf("- BRAKE: %d\n",
result.alertCounts[getComponentTypeIndex(BRAKE) - 1]);
printf("- AXLE: %d\n",
result.alertCounts[getComponentTypeIndex(AXLE) - 1]);
}
else
{
printf("NO COMPONENTS IN ALERT\n");
}
printf("WORN COMPONENTS: %d\n", result.wornCount);
if (result.wornCount >= MIN_WORN_FOR_WARNING)
{
printf("WAGON STATUS: NOT RELIABLE\n");
}
else
{
printf("WAGON STATUS: RELIABLE\n");
}
printf("----------------------------------------\n");
}
/* Exercise 3.1 */
char *getSensorAxleName(int position)
{
char *axleName;
if (position <= SENSORS_PER_AXLE)
{
axleName = "AXLE1";
}
else
{
axleName = "AXLE2";
}
return axleName;
}
/* Exercise 3.2 */
char *getComponentName(tComponentType compType)
{
char *name;
switch (compType)
{
case BEARING:
name = "BEARING";
break;
case WHEEL:
name = "WHEEL";
break;
case BRAKE:
name = "BRAKE";
break;
case AXLE:
name = "AXLE";
break;
default:
name = "UNKNOWN";
break;
}
return name;
}
To embed this project on your website, copy the following code and paste it into your website's HTML: