SensorValue alertValue;
AlertRule alertRule;
SensorPointer sensor;
CheckAlertTimeout checkTimeout;
CheckAlertTimeout currentTimeout;
};
std::map containerAlert; // (6)
std::thread pollThread_; // (7)
bool exit_; // (8)
std::mutex mutex_; // (9)
void poll(); // (10)
};
В строке 1 объявлен метод для запуска процесса отслеживания пороговых значений, в строке 2 – метод для останова. Метод в строке 3 добавляет датчик для отслеживания, метод 4 – удаляет.
В строке 5 объявлена структура, в которой хранятся данные, необходимые для отслеживания показаний датчика. В строке 6 объявлен контейнер для хранения указанных структур; метод addAlertдобавляет запись в контейнер, метод deleteAlertудаляет ее. В строке 7 объявлен класс для запуска потока для отслеживания, в строке 8 объявлен индикатор выхода, в строке 9 объявлен мьютекс для синхронизации.
Отслеживание показаний реализовано в методе, объявленном в строке 10. Поток отслеживания вызывает этот метод, который циклически опрашивает назначенные датчики и в случае превышения пороговых значений осуществляет обратный вызов. Реализация приведена в Листинг 96.
Листинг 96. Отслеживание пороговых значений
void Observer::poll()
{
using namespace std::chrono_literals;
while (!exit_) // (1)
{
std::this_thread::sleep_for(1s); // (2)
std::lock_guard lock(mutex_); // (3)
for (auto& item : containerAlert) // (4)
{
Alert& alert = item.second;
alert.currentTimeout++; // (5)
if (alert.checkTimeout != 0 && alert.currentTimeout >= alert.checkTimeout) // (6)
{
bool triggerAlert = false;
if (alert.alertRule == AlertRule::More) // (7)
{
triggerAlert = alert.sensor->getValue() > alert.alertValue;
}
else // (8)
{
triggerAlert = alert.sensor->getValue() < alert.alertValue;
}
if (triggerAlert) // (9)
{
alert.checkTimeout = alert.callback(item.first, alert.alertValue); // (10)
}
alert.currentTimeout = 0; // (11)
}
}
}
}
В строке 1 объявлен цикл опроса, который выполняется, пока не выставлен индикатор завершения (выставляется в методе stop). В строке 2 поток засыпает на 1 секунду, т. е. интервал опроса равен 1 секунде. В строке 3 блокируется мьютекс, чтобы избежать коллизий добавления/удаления элементов в контейнере.
В строке 4 осуществляется опрос элементов, хранящихся в контейнере. Текущее время опроса в строке 5 увеличивается на единицу. Если уведомление разрешено, о чем говорит ненулевое значение timeout, и время последнего опроса превысило назначенное время (строка 6), то тогда проверяется, имелось ли превышение пороговых значений в соответствии с назначенными правилами (строки 6, 7). Если превышение зафиксировано (строка 9), то осуществляется обратный вызов (строка 10). Этот вызов возвращает следующий интервал опроса, после чего текущее время сбрасывается (строка 11).
6.2.8. Интерфейсный класс
Класс, объявляющий интерфейс для взаимодействия с приложением, представлен в Листинг 97.
Листинг 97. Интерфейсный класс (ControlInterface.h)
namespace sensor
{
class ISensorControl
{
public:
virtual ~ ISensorControl () = default;
virtual void initialize() = 0; // (1)
virtual void shutDown() = 0; // (2)
virtual void assignDriver(DriverPointer driver) = 0; // (3)
virtual DriverPointer getAssignedDriver() = 0; // (4)
virtual DriverPointer getSensorDriver(SensorNumber number) = 0; // (5)
virtual void addSensor(SensorType type, SensorNumber number) = 0; // (6)
virtual void deleteSensor(SensorNumber number) = 0; // (7)
virtual bool isSensorExist(SensorNumber number) = 0; // (8)
virtual bool isSensorOperable(SensorNumber number) = 0; // (9)
virtual SensorValue getSensorValue(SensorNumber number) = 0; // (10)
virtual void querySensorValue(SensorNumber number, SensorValueCallback callback) = 0; // (11)
virtual void readSensorValues(SensorValueCallback callback) = 0; // (12)
virtual SensorValue getMinValue(SensorNumber first, SensorNumber last) = 0; // (13)
virtual SensorValue getMaxValue(SensorNumber first, SensorNumber last) = 0; // (14)
virtual void setAlert(SensorNumber number, SensorAlertCallback callback, SensorValue alertValue, AlertRule alertRule, CheckAlertTimeout checkTimeoutSeс = 1) = 0; // (15)
virtual void resetAlert(SensorNumber number) = 0; // (16)
static ISensorControl* createControl(); // (17)
};
};
В строке 1 и 2 объявлены методы для запуска и останова. В строках 3 и 4 объявлены методы для назначения и получения драйвера. Этот драйвер должен быть создан и назначен в самом начале работы, поскольку он будет передаваться новым создаваемым датчикам. Узнать назначенный драйвер для соответствующего датчика можно в методе 5.
В строках 6 и 7 объявлены методы для добавления и удаления датчика. В методе 8 можно проверить, существует ли датчик с переданным номером, в методе 9 можно проверить, является ли датчик работоспособным.
Читать дальше