// GLOBAL DEFINES ==============================================================
#define NULL ((void *)0)
#define FALSE 0
#define TRUE 1
#define LOW 0
#define HIGH 1
#define __STATIC static
#define HAL_INLINE __inline
#define ALWAYS_INLINE_ATTRIBUTE
#define ISO_OP_MEMORY_CLASS
#define wsd_ISOAgLibSE 0
#define alm_gps 2000
#define alm_wheel 2001
#define alm_fert 2002
#define alm_level_fert 2003
#define alm_level_seed 2004
#define skm_start 4000
#define msk_start 1000
// GLOBAL TYPE DEFINITIONS =====================================================
typedef void TVoid;
typedef void THandle;
typedef char TChar;
typedef signed char TInt8;
typedef signed short TInt16;
typedef signed int TInt32;
typedef unsigned char TBoolean;
typedef unsigned char TUint8;
typedef unsigned short TUint16;
typedef unsigned int TUint32;
typedef float TFloat32;
typedef double TFloat64;
#define GET_SEED_LEVEL_ENABLED_PIN 4
#define GET_FERT_LEVEL_ENABLED_PIN 2
#define GET_SEED_LEVEL_STATUS_PIN 32
#define GET_FERT_LEVEL_STATUS_PIN 33
#define SET_SEED_LEVEL_STATUS_PIN 19
#define SET_FERT_LEVEL_STATUS_PIN 21
#define GPS_SPEED 1
#define TIME_CHECK_ALARM 1000
#define TIME_RETURN_TO_CHECK_ALARM 10000
typedef enum
{
E_LOCAL_CF_1,
E_LOCAL_CF_2,
E_LOCAL_CF_3,
E_LOCAL_CF_4
} ELocalCf;
// Global variables
static TBoolean m_boGpsSpeedModule = FALSE;
static TBoolean m_boLastStatusGps = FALSE;
static TBoolean m_boAlarmMaskChanged = FALSE;
static TBoolean m_boAlarmConditionsStillPresent = FALSE;
static TBoolean m_boSeedAndFertNormal = FALSE;
static TBoolean m_boAudioRepeat = FALSE;
static TUint32 m_u32CurrentTime = 0;
static TUint32 m_u32TimeOfAlarmMaskChange = 0;
static TUint32 m_u32TimeOfLastCheckAlarm = 0;
static TUint32 m_u32LevelSeedCount = 0;
static TUint32 m_u32LevelFertCount = 0;
static TUint32 m_u32AlarmMaskChangedCount = 0;
static TUint32 m_u32AlarmMaskResetCount = 0;
static TUint16 m_u16LastDisplayedAlarm = 0;
static TUint32 m_u32TimeOfLastAlarmDisplay = 0;
TUint32 u32IsoStackCoreGetTime()
{
return millis();
}
TBoolean vEcuAppCheckCrashingFert()
{
return FALSE;
}
TBoolean vEcuAppCheckStatusGps()
{
return TRUE;
}
TBoolean bEcuAppSeedLevelEnabled()
{
return digitalRead(GET_SEED_LEVEL_ENABLED_PIN);
}
TBoolean bEcuAppFertLevelEnabled()
{
return digitalRead(GET_FERT_LEVEL_ENABLED_PIN);
}
TBoolean bEcuAppGetSeedLevelStatus()
{
return !digitalRead(GET_SEED_LEVEL_STATUS_PIN);
}
TBoolean bEcuAppGetFertLevelStatus()
{
return !digitalRead(GET_FERT_LEVEL_STATUS_PIN);
}
void vTriggerAlarm(TUint16 alarmType)
{
// Auxiliary function to trigger an alarm
// Change the active mask to the specified alarm type
eIsoStackVtQChangeActiveMask(E_LOCAL_CF_1, wsd_ISOAgLibSE, alarmType, 0);
// Set the alarm mask changed flag to TRUE
m_boAlarmMaskChanged = TRUE;
// Update the time of the alarm mask change to the current time
m_u32TimeOfAlarmMaskChange = m_u32CurrentTime;
// Reset the audio repeat flag
m_boAudioRepeat = FALSE;
// Reset alarm count
m_u32AlarmMaskChangedCount = 0;
// Switch case to handle different alarm types
switch (alarmType) {
case alm_fert:
// Fertilizer crash detected
Serial.println("Alert: Fertilizer crash detected!");
break;
case alm_gps:
// GPS status issue detected
Serial.println("Alert: GPS status is not OK!");
break;
case alm_level_seed:
// Seed level status issue detected
Serial.printf("Alert (%d): Seed level status is not OK\n", ++m_u32LevelSeedCount);
break;
case alm_level_fert:
// Fertilizer level status issue detected
Serial.printf("Alert (%d): Fertilizer level status is not OK\n", ++m_u32LevelSeedCount);
break;
default:
// Unknown alarm type detected
Serial.println("Alert: Unknown alarm type!");
break;
}
}
void eIsoStackVtQChangeActiveMask(
ELocalCf eLocalCf,
TUint16 u16WorkingSetObjId,
TUint16 u16NewActiveMaskObjId,
TUint32 u32UserId)
{
// Check if the new active mask object ID is equal to the start mask
if (u16NewActiveMaskObjId == msk_start) {
// If it is, set the seed level status pin and fertilizer level status pin to LOW
digitalWrite(SET_SEED_LEVEL_STATUS_PIN, LOW);
digitalWrite(SET_FERT_LEVEL_STATUS_PIN, LOW);
}
// Check if the new active mask object ID is equal to the seed level alarm mask
else if (u16NewActiveMaskObjId == alm_level_seed) {
// If it is, set the seed level status pin to HIGH and fertilizer level status pin to LOW
digitalWrite(SET_SEED_LEVEL_STATUS_PIN, HIGH);
digitalWrite(SET_FERT_LEVEL_STATUS_PIN, LOW);
}
// Check if the new active mask object ID is equal to another condition (it seems like there might be a mistake here because the condition is the same as the previous one)
else if (u16NewActiveMaskObjId == alm_level_fert) { // Possibly, this condition should be different
// If it is, set both the seed level status pin and fertilizer level status pin to LOW
digitalWrite(SET_SEED_LEVEL_STATUS_PIN, LOW);
digitalWrite(SET_FERT_LEVEL_STATUS_PIN, HIGH);
}
}
TUint8 u8EcuAppSpeedModule()
{
return GPS_SPEED;
}
TVoid vResetAlarmMask()
{
// Auxiliary function to reset the alarm mask
if (m_boAlarmMaskChanged) {
Serial.printf("Alarm mask has changed (%d)\n", ++m_u32AlarmMaskChangedCount); // Indicate that the alarm mask has changed
// Check if any of the alarm conditions are still present
m_boAlarmConditionsStillPresent = vEcuAppCheckCrashingFert() ||
(m_boGpsSpeedModule && !vEcuAppCheckStatusGps()) ||
(bEcuAppSeedLevelEnabled() && !bEcuAppGetSeedLevelStatus()) ||
(bEcuAppFertLevelEnabled() && !bEcuAppGetFertLevelStatus());
// Check if seed and fert levels are back to normal
m_boSeedAndFertNormal = bEcuAppGetSeedLevelStatus() && bEcuAppGetFertLevelStatus();
// Reset the alarm mask if no alarm conditions are present or if seed and fert levels are back to normal
if (!m_boAlarmConditionsStillPresent || m_boSeedAndFertNormal ||
// or if the predefined time to check the alarm has passed
(m_u32CurrentTime - m_u32TimeOfAlarmMaskChange) >= TIME_RETURN_TO_CHECK_ALARM) {
m_u32TimeOfAlarmMaskChange = u32IsoStackCoreGetTime();
m_boAlarmMaskChanged = FALSE; // Reset the alarm mask flag
m_u32AlarmMaskChangedCount = 0;
Serial.printf("Resetting alarm mask (%d)\n", ++m_u32AlarmMaskResetCount); // Indicate that the alarm mask is being reset
// Set the active mask back to the start mask, indicating that the alarm has been addressed
eIsoStackVtQChangeActiveMask(E_LOCAL_CF_1, wsd_ISOAgLibSE, msk_start, 0);
}
}
}
TVoid vVtAppCheckAlarm(TVoid)
{
// Get current time
m_u32CurrentTime = u32IsoStackCoreGetTime();
// Exit early if the alarm check interval hasn't passed
if ((m_u32CurrentTime - m_u32TimeOfLastCheckAlarm) < TIME_CHECK_ALARM) {
return;
}
// Update the last check time
m_u32TimeOfLastCheckAlarm = m_u32CurrentTime;
// Determine the type of speed module being used
m_boGpsSpeedModule = u8EcuAppSpeedModule() == GPS_SPEED;
// Check and trigger alarms if conditions are met and no alarm is currently active
if (!m_boAlarmMaskChanged ||
(m_u32CurrentTime - m_u32TimeOfLastAlarmDisplay) >= TIME_RETURN_TO_CHECK_ALARM) {
// Reset the last alarm display time
m_u32TimeOfLastAlarmDisplay = m_u32CurrentTime;
if (vEcuAppCheckCrashingFert()) {
vTriggerAlarm(alm_fert);
}
else if (m_boGpsSpeedModule && !vEcuAppCheckStatusGps()) {
vTriggerAlarm(alm_gps);
}
else if (bEcuAppSeedLevelEnabled() && !bEcuAppGetSeedLevelStatus() &&
(m_u16LastDisplayedAlarm != alm_level_seed || !bEcuAppFertLevelEnabled() || bEcuAppGetFertLevelStatus())) {
vTriggerAlarm(alm_level_seed);
m_u16LastDisplayedAlarm = alm_level_seed;
}
else if (bEcuAppFertLevelEnabled() && !bEcuAppGetFertLevelStatus() &&
(m_u16LastDisplayedAlarm != alm_level_fert || !bEcuAppSeedLevelEnabled() || bEcuAppGetSeedLevelStatus())) {
vTriggerAlarm(alm_level_fert);
m_u16LastDisplayedAlarm = alm_level_fert;
}
}
// Reset the alarm mask based on conditions
vResetAlarmMask();
}
void setup()
{
Serial.begin(115200);
pinMode(GET_SEED_LEVEL_ENABLED_PIN, INPUT_PULLUP);
pinMode(GET_FERT_LEVEL_ENABLED_PIN, INPUT_PULLUP);
pinMode(GET_SEED_LEVEL_STATUS_PIN, INPUT_PULLUP);
pinMode(GET_FERT_LEVEL_STATUS_PIN, INPUT_PULLUP);
pinMode(SET_SEED_LEVEL_STATUS_PIN, OUTPUT);
pinMode(SET_FERT_LEVEL_STATUS_PIN, OUTPUT);
}
void loop()
{
vVtAppCheckAlarm();
}