#include "types.h" #include "hal.h" #include "ErrorManager.h" #include "TaskManager.h" #include #include class TemperatureMonitor { public: struct SensorInfo { int32_t temperature; uint32_t time; }; // Definition of constants. enum { IDLE_PERIOD_MS = 500, SENSOR_COUNT = 9, DELAYED_TIME_DELTA_MS = 20, TIMEOUT_TIME_DELTA_MS = 500, TIMEOUT_CHECKER_TASK_CYCLE_TIME_MS = 100, }; TemperatureMonitor(int32_t temperatureMin, int32_t temperatureMax, ErrorManager* errorManager, TaskManager* taskManager); void sensorMessageReceived(size_t sensor, int32_t temperature); void checkerTask(); const SensorInfo* getSensorInfos() const; private: TemperatureMonitor(); SensorInfo m_sensorInfos[SENSOR_COUNT]; int32_t m_temperatureMin; int32_t m_temperatureMax; bool m_idlePeriod; uint32_t m_initialTime; ErrorManager* m_errorManager; uint32_t timeDiffMillis(uint32_t earlierTime, uint32_t laterTime) const; uint32_t getTimeMillis() const; }; TemperatureMonitor::TemperatureMonitor(int32_t temperatureMin, int32_t temperatureMax, ErrorManager* errorManager, TaskManager* taskManager) { assert(errorManager != NULL); assert(taskManager != NULL); memset(m_sensorInfos, 0, sizeof(m_sensorInfos)); m_temperatureMin = temperatureMin; m_temperatureMax = temperatureMax; m_idlePeriod = true; m_initialTime = getTimeMillis(); m_errorManager = errorManager; // Finally, start cyclic task. taskManager->scheduleCyclicTask(this, &TemperatureMonitor::checkerTask, TIMEOUT_CHECKER_TASK_CYCLE_TIME_MS); } // Called-back by the bus controller upon arrival of a temperature controller // message. void TemperatureMonitor::sensorMessageReceived(size_t sensor, int32_t temperature) { if (sensor < SENSOR_COUNT) { uint32_t time = getTimeMillis(); SensorInfo* sensorInfo = &m_sensorInfos[sensor]; DISABLE_INTERRUPTS(); if (m_idlePeriod) { // Don't check (only store) during idle period. } else { if (timeDiffMillis(sensorInfo->time, time) > DELAYED_TIME_DELTA_MS) { m_errorManager->reportDelay(sensor); } if (sensorInfo->temperature < m_temperatureMin) { m_errorManager->reportTooLow(sensor); } else if (sensorInfo->temperature > m_temperatureMax) { m_errorManager->reportTooHigh(sensor); } } sensorInfo->temperature = temperature; sensorInfo->time = time; ENABLE_INTERRUPTS(); } else { m_errorManager->reportInvalidSensorIndex(sensor); } } void TemperatureMonitor::checkerTask() { uint32_t time = getTimeMillis(); DISABLE_INTERRUPTS(); // do-while(0) allows for 'breaking-out' to common/clean-up code. do { if (m_idlePeriod) { // End of idle period reached? if (timeDiffMillis(m_initialTime, time) > IDLE_PERIOD_MS) { m_idlePeriod = false; // Do nothing during idle period. } else { break; } } for (size_t sensor = 0; sensor < SENSOR_COUNT; ++sensor) { if (timeDiffMillis(m_sensorInfos[sensor].time, time) > TIMEOUT_TIME_DELTA_MS) { m_errorManager->reportTimeout(sensor); } } } while (0); ENABLE_INTERRUPTS(); } const TemperatureMonitor::SensorInfo* TemperatureMonitor::getSensorInfos() const { return m_idlePeriod ? NULL : m_sensorInfos; } uint32_t TemperatureMonitor::timeDiffMillis(uint32_t earlierTime, uint32_t laterTime) const { uint32_t diff; // Normal case, no wrap-around. if (earlierTime <= laterTime) { diff = laterTime - earlierTime; // 'laterTime' has wrapped-around 32-bit boundary. } else { diff = (0xFFFFFFFF - earlierTime) + laterTime; } return diff; } uint32_t TemperatureMonitor::getTimeMillis() const { uint32_t ticks = HalGetClockTicks(); uint32_t micros = ticks / HAL_CLOCK_FREQUENCY_MHZ; uint32_t millis = micros / 1000; return millis; }