mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-27 06:50:21 +00:00
DHT monitor remove
This commit is contained in:
parent
cbc9720738
commit
453666192c
10 changed files with 0 additions and 1356 deletions
|
@ -1,169 +0,0 @@
|
||||||
#include "DHT.h"
|
|
||||||
|
|
||||||
#define lineDown() furi_hal_gpio_write(sensor->GPIO, false)
|
|
||||||
#define lineUp() furi_hal_gpio_write(sensor->GPIO, true)
|
|
||||||
#define getLine() furi_hal_gpio_read(sensor->GPIO)
|
|
||||||
#define Delay(d) furi_delay_ms(d)
|
|
||||||
|
|
||||||
DHT_data DHT_getData(DHT_sensor* sensor) {
|
|
||||||
DHT_data data = {-128.0f, -128.0f};
|
|
||||||
|
|
||||||
#if DHT_POLLING_CONTROL == 1
|
|
||||||
/* Ограничение по частоте опроса датчика */
|
|
||||||
//Определение интервала опроса в зависимости от датчика
|
|
||||||
uint16_t pollingInterval;
|
|
||||||
if(sensor->type == DHT11) {
|
|
||||||
pollingInterval = DHT_POLLING_INTERVAL_DHT11;
|
|
||||||
} else {
|
|
||||||
pollingInterval = DHT_POLLING_INTERVAL_DHT22;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Если интервал маленький, то возврат последнего удачного значения
|
|
||||||
if((furi_get_tick() - sensor->lastPollingTime < pollingInterval) &&
|
|
||||||
sensor->lastPollingTime != 0) {
|
|
||||||
data.hum = sensor->lastHum;
|
|
||||||
data.temp = sensor->lastTemp;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
sensor->lastPollingTime = furi_get_tick() + 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//Опускание линии данных на 18 мс
|
|
||||||
lineDown();
|
|
||||||
#ifdef DHT_IRQ_CONTROL
|
|
||||||
//Выключение прерываний, чтобы ничто не мешало обработке данных
|
|
||||||
__disable_irq();
|
|
||||||
#endif
|
|
||||||
Delay(18);
|
|
||||||
|
|
||||||
//Подъём линии
|
|
||||||
lineUp();
|
|
||||||
|
|
||||||
/* Ожидание ответа от датчика */
|
|
||||||
uint16_t timeout = 0;
|
|
||||||
while(!getLine()) {
|
|
||||||
timeout++;
|
|
||||||
if(timeout > DHT_TIMEOUT) {
|
|
||||||
#ifdef DHT_IRQ_CONTROL
|
|
||||||
__enable_irq();
|
|
||||||
#endif
|
|
||||||
//Если датчик не отозвался, значит его точно нет
|
|
||||||
//Обнуление последнего удачного значения, чтобы
|
|
||||||
//не получать фантомные значения
|
|
||||||
sensor->lastHum = -128.0f;
|
|
||||||
sensor->lastTemp = -128.0f;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Ожидание спада
|
|
||||||
while(getLine()) {
|
|
||||||
timeout++;
|
|
||||||
if(timeout > DHT_TIMEOUT) {
|
|
||||||
#ifdef DHT_IRQ_CONTROL
|
|
||||||
__enable_irq();
|
|
||||||
#endif
|
|
||||||
//Если датчик не отозвался, значит его точно нет
|
|
||||||
//Обнуление последнего удачного значения, чтобы
|
|
||||||
//не получать фантомные значения
|
|
||||||
sensor->lastHum = -128.0f;
|
|
||||||
sensor->lastTemp = -128.0f;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
timeout = 0;
|
|
||||||
//Ожидание подъёма
|
|
||||||
while(!getLine()) {
|
|
||||||
timeout++;
|
|
||||||
if(timeout > DHT_TIMEOUT) {
|
|
||||||
if(timeout > DHT_TIMEOUT) {
|
|
||||||
#ifdef DHT_IRQ_CONTROL
|
|
||||||
__enable_irq();
|
|
||||||
#endif
|
|
||||||
//Если датчик не отозвался, значит его точно нет
|
|
||||||
//Обнуление последнего удачного значения, чтобы
|
|
||||||
//не получать фантомные значения
|
|
||||||
sensor->lastHum = -128.0f;
|
|
||||||
sensor->lastTemp = -128.0f;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
timeout = 0;
|
|
||||||
//Ожидание спада
|
|
||||||
while(getLine()) {
|
|
||||||
timeout++;
|
|
||||||
if(timeout > DHT_TIMEOUT) {
|
|
||||||
#ifdef DHT_IRQ_CONTROL
|
|
||||||
__enable_irq();
|
|
||||||
#endif
|
|
||||||
//Если датчик не отозвался, значит его точно нет
|
|
||||||
//Обнуление последнего удачного значения, чтобы
|
|
||||||
//не получать фантомные значения
|
|
||||||
sensor->lastHum = -128.0f;
|
|
||||||
sensor->lastTemp = -128.0f;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Чтение ответа от датчика */
|
|
||||||
uint8_t rawData[5] = {0, 0, 0, 0, 0};
|
|
||||||
for(uint8_t a = 0; a < 5; a++) {
|
|
||||||
for(uint8_t b = 7; b != 255; b--) {
|
|
||||||
uint16_t hT = 0, lT = 0;
|
|
||||||
//Пока линия в низком уровне, инкремент переменной lT
|
|
||||||
while(!getLine() && lT != 65535) lT++;
|
|
||||||
//Пока линия в высоком уровне, инкремент переменной hT
|
|
||||||
timeout = 0;
|
|
||||||
while(getLine() && hT != 65535) hT++;
|
|
||||||
//Если hT больше lT, то пришла единица
|
|
||||||
if(hT > lT) rawData[a] |= (1 << b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef DHT_IRQ_CONTROL
|
|
||||||
//Включение прерываний после приёма данных
|
|
||||||
__enable_irq();
|
|
||||||
#endif
|
|
||||||
/* Проверка целостности данных */
|
|
||||||
if((uint8_t)(rawData[0] + rawData[1] + rawData[2] + rawData[3]) == rawData[4]) {
|
|
||||||
//Если контрольная сумма совпадает, то конвертация и возврат полученных значений
|
|
||||||
if(sensor->type == DHT22) {
|
|
||||||
data.hum = (float)(((uint16_t)rawData[0] << 8) | rawData[1]) * 0.1f;
|
|
||||||
//Проверка на отрицательность температуры
|
|
||||||
if(!(rawData[2] & (1 << 7))) {
|
|
||||||
data.temp = (float)(((uint16_t)rawData[2] << 8) | rawData[3]) * 0.1f;
|
|
||||||
} else {
|
|
||||||
rawData[2] &= ~(1 << 7);
|
|
||||||
data.temp = (float)(((uint16_t)rawData[2] << 8) | rawData[3]) * -0.1f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(sensor->type == DHT11) {
|
|
||||||
data.hum = (float)rawData[0];
|
|
||||||
data.temp = (float)rawData[2];
|
|
||||||
//DHT11 производства ASAIR имеют дробную часть в температуре
|
|
||||||
//А ещё температуру измеряет от -20 до +60 *С
|
|
||||||
//Вот прикол, да?
|
|
||||||
if(rawData[3] != 0) {
|
|
||||||
//Проверка знака
|
|
||||||
if(!(rawData[3] & (1 << 7))) {
|
|
||||||
//Добавление положительной дробной части
|
|
||||||
data.temp += rawData[3] * 0.1f;
|
|
||||||
} else {
|
|
||||||
//А тут делаем отрицательное значение
|
|
||||||
rawData[3] &= ~(1 << 7);
|
|
||||||
data.temp += rawData[3] * 0.1f;
|
|
||||||
data.temp *= -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DHT_POLLING_CONTROL == 1
|
|
||||||
sensor->lastHum = data.hum;
|
|
||||||
sensor->lastTemp = data.temp;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
#ifndef DHT_H_
|
|
||||||
#define DHT_H_
|
|
||||||
|
|
||||||
#include <furi_hal_resources.h>
|
|
||||||
|
|
||||||
/* Настройки */
|
|
||||||
#define DHT_TIMEOUT 65534 //Количество итераций, после которых функция вернёт пустые значения
|
|
||||||
#define DHT_POLLING_CONTROL 1 //Включение проверки частоты опроса датчика
|
|
||||||
#define DHT_POLLING_INTERVAL_DHT11 \
|
|
||||||
2000 //Интервал опроса DHT11 (0.5 Гц по даташиту). Можно поставить 1500, будет работать
|
|
||||||
//Костыль, временно 2 секунды для датчика AM2302
|
|
||||||
#define DHT_POLLING_INTERVAL_DHT22 2000 //Интервал опроса DHT22 (1 Гц по даташиту)
|
|
||||||
#define DHT_IRQ_CONTROL //Выключать прерывания во время обмена данных с датчиком
|
|
||||||
/* Структура возвращаемых датчиком данных */
|
|
||||||
typedef struct {
|
|
||||||
float hum;
|
|
||||||
float temp;
|
|
||||||
} DHT_data;
|
|
||||||
|
|
||||||
/* Тип используемого датчика */
|
|
||||||
typedef enum { DHT11, DHT22 } DHT_type;
|
|
||||||
|
|
||||||
/* Структура объекта датчика */
|
|
||||||
typedef struct {
|
|
||||||
char name[11];
|
|
||||||
const GpioPin* GPIO; //Пин датчика
|
|
||||||
DHT_type type; //Тип датчика (DHT11 или DHT22)
|
|
||||||
|
|
||||||
//Контроль частоты опроса датчика. Значения не заполнять!
|
|
||||||
#if DHT_POLLING_CONTROL == 1
|
|
||||||
uint32_t lastPollingTime; //Время последнего опроса датчика
|
|
||||||
float lastTemp; //Последнее значение температуры
|
|
||||||
float lastHum; //Последнее значение влажности
|
|
||||||
#endif
|
|
||||||
} DHT_sensor;
|
|
||||||
|
|
||||||
/* Прототипы функций */
|
|
||||||
DHT_data DHT_getData(DHT_sensor* sensor); //Получить данные с датчика
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,13 +0,0 @@
|
||||||
App(
|
|
||||||
appid="quenon_dht_mon",
|
|
||||||
name="[DHT] Temp. Monitor",
|
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
|
||||||
entry_point="quenon_dht_mon_app",
|
|
||||||
cdefines=["QUENON_DHT_MON"],
|
|
||||||
requires=[
|
|
||||||
"gui",
|
|
||||||
],
|
|
||||||
fap_category="GPIO",
|
|
||||||
fap_icon="icon.png",
|
|
||||||
stack_size=2 * 1024,
|
|
||||||
)
|
|
Binary file not shown.
Before Width: | Height: | Size: 136 B |
|
@ -1,464 +0,0 @@
|
||||||
#include "quenon_dht_mon.h"
|
|
||||||
#include <m-string.h>
|
|
||||||
|
|
||||||
//Порты ввода/вывода, которые не были обозначены в общем списке
|
|
||||||
const GpioPin SWC_10 = {.pin = LL_GPIO_PIN_14, .port = GPIOA};
|
|
||||||
const GpioPin SIO_12 = {.pin = LL_GPIO_PIN_13, .port = GPIOA};
|
|
||||||
const GpioPin TX_13 = {.pin = LL_GPIO_PIN_6, .port = GPIOB};
|
|
||||||
const GpioPin RX_14 = {.pin = LL_GPIO_PIN_7, .port = GPIOB};
|
|
||||||
|
|
||||||
//Количество доступных портов ввода/вывода
|
|
||||||
#define GPIO_ITEMS (sizeof(gpio_item) / sizeof(GpioItem))
|
|
||||||
|
|
||||||
//Перечень достуных портов ввода/вывода
|
|
||||||
static const GpioItem gpio_item[] = {
|
|
||||||
{2, "2 (A7)", &gpio_ext_pa7},
|
|
||||||
{3, "3 (A6)", &gpio_ext_pa6},
|
|
||||||
{4, "4 (A4)", &gpio_ext_pa4},
|
|
||||||
{5, "5 (B3)", &gpio_ext_pb3},
|
|
||||||
{6, "6 (B2)", &gpio_ext_pb2},
|
|
||||||
{7, "7 (C3)", &gpio_ext_pc3},
|
|
||||||
{10, " 10(SWC) ", &SWC_10},
|
|
||||||
{12, "12 (SIO)", &SIO_12},
|
|
||||||
{13, "13 (TX)", &TX_13},
|
|
||||||
{14, "14 (RX)", &RX_14},
|
|
||||||
{15, "15 (C1)", &gpio_ext_pc1},
|
|
||||||
{16, "16 (C0)", &gpio_ext_pc0},
|
|
||||||
{17, "17 (1W)", &ibutton_gpio}};
|
|
||||||
|
|
||||||
//Данные плагина
|
|
||||||
static PluginData* app;
|
|
||||||
|
|
||||||
uint8_t DHTMon_GPIO_to_int(const GpioPin* gpio) {
|
|
||||||
if(gpio == NULL) return 255;
|
|
||||||
for(uint8_t i = 0; i < GPIO_ITEMS; i++) {
|
|
||||||
if(gpio_item[i].pin->pin == gpio->pin && gpio_item[i].pin->port == gpio->port) {
|
|
||||||
return gpio_item[i].num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
const GpioPin* DHTMon_GPIO_form_int(uint8_t name) {
|
|
||||||
for(uint8_t i = 0; i < GPIO_ITEMS; i++) {
|
|
||||||
if(gpio_item[i].num == name) {
|
|
||||||
return gpio_item[i].pin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const GpioPin* DHTMon_GPIO_from_index(uint8_t index) {
|
|
||||||
if(index > GPIO_ITEMS) return NULL;
|
|
||||||
return gpio_item[index].pin;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t DHTMon_GPIO_to_index(const GpioPin* gpio) {
|
|
||||||
if(gpio == NULL) return 255;
|
|
||||||
for(uint8_t i = 0; i < GPIO_ITEMS; i++) {
|
|
||||||
if(gpio_item[i].pin->pin == gpio->pin && gpio_item[i].pin->port == gpio->port) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* DHTMon_GPIO_getName(const GpioPin* gpio) {
|
|
||||||
if(gpio == NULL) return NULL;
|
|
||||||
for(uint8_t i = 0; i < GPIO_ITEMS; i++) {
|
|
||||||
if(gpio_item[i].pin->pin == gpio->pin && gpio_item[i].pin->port == gpio->port) {
|
|
||||||
return gpio_item[i].name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DHTMon_sensors_init(void) {
|
|
||||||
//Включение 5V если на порту 1 FZ его нет
|
|
||||||
if(furi_hal_power_is_otg_enabled() != true) {
|
|
||||||
furi_hal_power_enable_otg();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Настройка GPIO загруженных датчиков
|
|
||||||
for(uint8_t i = 0; i < app->sensors_count; i++) {
|
|
||||||
//Высокий уровень по умолчанию
|
|
||||||
furi_hal_gpio_write(app->sensors[i].GPIO, true);
|
|
||||||
//Режим работы - OpenDrain, подтяжка включается на всякий случай
|
|
||||||
furi_hal_gpio_init(
|
|
||||||
app->sensors[i].GPIO, //Порт FZ
|
|
||||||
GpioModeOutputOpenDrain, //Режим работы - открытый сток
|
|
||||||
GpioPullUp, //Принудительная подтяжка линии данных к питанию
|
|
||||||
GpioSpeedVeryHigh); //Скорость работы - максимальная
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DHTMon_sensors_deinit(void) {
|
|
||||||
//Возврат исходного состояния 5V
|
|
||||||
if(app->last_OTG_State != true) {
|
|
||||||
furi_hal_power_disable_otg();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Перевод портов GPIO в состояние по умолчанию
|
|
||||||
for(uint8_t i = 0; i < app->sensors_count; i++) {
|
|
||||||
furi_hal_gpio_init(
|
|
||||||
app->sensors[i].GPIO, //Порт FZ
|
|
||||||
GpioModeAnalog, //Режим работы - аналог
|
|
||||||
GpioPullNo, //Отключение подтяжки
|
|
||||||
GpioSpeedLow); //Скорость работы - низкая
|
|
||||||
//Установка низкого уровня
|
|
||||||
furi_hal_gpio_write(app->sensors[i].GPIO, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DHTMon_sensor_check(DHT_sensor* sensor) {
|
|
||||||
/* Проверка имени */
|
|
||||||
//1) Строка должна быть длиной от 1 до 10 символов
|
|
||||||
//2) Первый символ строки должен быть только 0-9, A-Z, a-z и _
|
|
||||||
if(strlen(sensor->name) == 0 || strlen(sensor->name) > 10 ||
|
|
||||||
(!(sensor->name[0] >= '0' && sensor->name[0] <= '9') &&
|
|
||||||
!(sensor->name[0] >= 'A' && sensor->name[0] <= 'Z') &&
|
|
||||||
!(sensor->name[0] >= 'a' && sensor->name[0] <= 'z') && !(sensor->name[0] == '_'))) {
|
|
||||||
FURI_LOG_D(APP_NAME, "Sensor [%s] name check failed\r\n", sensor->name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//Проверка GPIO
|
|
||||||
if(DHTMon_GPIO_to_int(sensor->GPIO) == 255) {
|
|
||||||
FURI_LOG_D(
|
|
||||||
APP_NAME,
|
|
||||||
"Sensor [%s] GPIO check failed: %d\r\n",
|
|
||||||
sensor->name,
|
|
||||||
DHTMon_GPIO_to_int(sensor->GPIO));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//Проверка типа датчика
|
|
||||||
if(sensor->type != DHT11 && sensor->type != DHT22) {
|
|
||||||
FURI_LOG_D(APP_NAME, "Sensor [%s] type check failed: %d\r\n", sensor->name, sensor->type);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Возврат истины если всё ок
|
|
||||||
FURI_LOG_D(APP_NAME, "Sensor [%s] all checks passed\r\n", sensor->name);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DHTMon_sensor_delete(DHT_sensor* sensor) {
|
|
||||||
if(sensor == NULL) return;
|
|
||||||
//Делаем параметры датчика неверными
|
|
||||||
sensor->name[0] = '\0';
|
|
||||||
sensor->type = 255;
|
|
||||||
//Теперь сохраняем текущие датчики. Сохранятор не сохранит неисправный датчик
|
|
||||||
DHTMon_sensors_save();
|
|
||||||
//Перезагружаемся с SD-карты
|
|
||||||
DHTMon_sensors_reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t DHTMon_sensors_save(void) {
|
|
||||||
//Выделение памяти для потока
|
|
||||||
app->file_stream = file_stream_alloc(app->storage);
|
|
||||||
uint8_t savedSensorsCount = 0;
|
|
||||||
//Переменная пути к файлу
|
|
||||||
FuriString* filepath = furi_string_alloc();
|
|
||||||
//Составление пути к файлу
|
|
||||||
furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME);
|
|
||||||
|
|
||||||
//Открытие потока. Если поток открылся, то выполнение сохранения датчиков
|
|
||||||
if(file_stream_open(
|
|
||||||
app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)) {
|
|
||||||
const char template[] =
|
|
||||||
"#DHT monitor sensors file\n#Name - name of sensor. Up to 10 sumbols\n#Type - type of sensor. DHT11 - 0, DHT22 - 1\n#GPIO - connection port. May being 2-7, 10, 12-17\n#Name Type GPIO\n";
|
|
||||||
stream_write(app->file_stream, (uint8_t*)template, strlen(template));
|
|
||||||
//Сохранение датчиков
|
|
||||||
for(uint8_t i = 0; i < app->sensors_count; i++) {
|
|
||||||
//Если параметры датчика верны, то сохраняемся
|
|
||||||
if(DHTMon_sensor_check(&app->sensors[i])) {
|
|
||||||
stream_write_format(
|
|
||||||
app->file_stream,
|
|
||||||
"%s %d %d\n",
|
|
||||||
app->sensors[i].name,
|
|
||||||
app->sensors[i].type,
|
|
||||||
DHTMon_GPIO_to_int(app->sensors[i].GPIO));
|
|
||||||
savedSensorsCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//TODO: печать ошибки на экран
|
|
||||||
FURI_LOG_E(APP_NAME, "cannot create sensors file\r\n");
|
|
||||||
}
|
|
||||||
stream_free(app->file_stream);
|
|
||||||
|
|
||||||
return savedSensorsCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DHTMon_sensors_load(void) {
|
|
||||||
//Обнуление количества датчиков
|
|
||||||
app->sensors_count = -1;
|
|
||||||
//Очистка предыдущих датчиков
|
|
||||||
memset(app->sensors, 0, sizeof(app->sensors));
|
|
||||||
|
|
||||||
//Открытие файла на SD-карте
|
|
||||||
//Выделение памяти для потока
|
|
||||||
app->file_stream = file_stream_alloc(app->storage);
|
|
||||||
//Переменная пути к файлу
|
|
||||||
FuriString* filepath = furi_string_alloc();
|
|
||||||
//Составление пути к файлу
|
|
||||||
furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME);
|
|
||||||
//Открытие потока к файлу
|
|
||||||
if(!file_stream_open(
|
|
||||||
app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) {
|
|
||||||
//Если файл отсутствует, то создание болванки
|
|
||||||
FURI_LOG_W(APP_NAME, "Missing sensors file. Creating new file\r\n");
|
|
||||||
app->sensors_count = 0;
|
|
||||||
stream_free(app->file_stream);
|
|
||||||
DHTMon_sensors_save();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//Вычисление размера файла
|
|
||||||
size_t file_size = stream_size(app->file_stream);
|
|
||||||
if(file_size == (size_t)0) {
|
|
||||||
//Выход если файл пустой
|
|
||||||
FURI_LOG_W(APP_NAME, "Sensors file is empty\r\n");
|
|
||||||
app->sensors_count = 0;
|
|
||||||
stream_free(app->file_stream);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Выделение памяти под загрузку файла
|
|
||||||
uint8_t* file_buf = malloc(file_size);
|
|
||||||
//Опустошение буфера файла
|
|
||||||
memset(file_buf, 0, file_size);
|
|
||||||
//Загрузка файла
|
|
||||||
if(stream_read(app->file_stream, file_buf, file_size) != file_size) {
|
|
||||||
//Выход при ошибке чтения
|
|
||||||
FURI_LOG_E(APP_NAME, "Error reading sensor file\r\n");
|
|
||||||
app->sensors_count = 0;
|
|
||||||
stream_free(app->file_stream);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//Построчное чтение файла
|
|
||||||
//Указатель на начало строки
|
|
||||||
FuriString* file = furi_string_alloc_set_str((char*)file_buf);
|
|
||||||
//Сколько байт до конца строки
|
|
||||||
size_t line_end = 0;
|
|
||||||
while(line_end != STRING_FAILURE && app->sensors_count < MAX_SENSORS) {
|
|
||||||
if(((char*)(file_buf + line_end))[1] != '#') {
|
|
||||||
DHT_sensor s = {0};
|
|
||||||
int type, port;
|
|
||||||
char name[11] = {0};
|
|
||||||
sscanf(((char*)(file_buf + line_end)), "%s %d %d", name, &type, &port);
|
|
||||||
s.type = type;
|
|
||||||
s.GPIO = DHTMon_GPIO_form_int(port);
|
|
||||||
|
|
||||||
name[10] = '\0';
|
|
||||||
strcpy(s.name, name);
|
|
||||||
//Если данные корректны, то
|
|
||||||
if(DHTMon_sensor_check(&s) == true) {
|
|
||||||
//Установка нуля при первом датчике
|
|
||||||
if(app->sensors_count == -1) app->sensors_count = 0;
|
|
||||||
//Добавление датчика в общий список
|
|
||||||
app->sensors[app->sensors_count] = s;
|
|
||||||
//Увеличение количества загруженных датчиков
|
|
||||||
app->sensors_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
line_end = furi_string_search_char(file, '\n', line_end + 1);
|
|
||||||
}
|
|
||||||
stream_free(app->file_stream);
|
|
||||||
free(file_buf);
|
|
||||||
|
|
||||||
//Обнуление количества датчиков если ни один из них не был загружен
|
|
||||||
if(app->sensors_count == -1) app->sensors_count = 0;
|
|
||||||
|
|
||||||
//Инициализация портов датчиков если таковые есть
|
|
||||||
if(app->sensors_count > 0) {
|
|
||||||
DHTMon_sensors_init();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DHTMon_sensors_reload(void) {
|
|
||||||
DHTMon_sensors_deinit();
|
|
||||||
return DHTMon_sensors_load();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Обработчик отрисовки экрана
|
|
||||||
*
|
|
||||||
* @param canvas Указатель на холст
|
|
||||||
* @param ctx Данные плагина
|
|
||||||
*/
|
|
||||||
static void render_callback(Canvas* const canvas, void* ctx) {
|
|
||||||
PluginData* app = acquire_mutex((ValueMutex*)ctx, 25);
|
|
||||||
if(app == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//Вызов отрисовки главного экрана
|
|
||||||
scene_main(canvas, app);
|
|
||||||
|
|
||||||
release_mutex((ValueMutex*)ctx, app);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Обработчик нажатия кнопок главного экрана
|
|
||||||
*
|
|
||||||
* @param input_event Указатель на событие
|
|
||||||
* @param event_queue Указатель на очередь событий
|
|
||||||
*/
|
|
||||||
static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
|
||||||
furi_assert(event_queue);
|
|
||||||
|
|
||||||
PluginEvent event = {.type = EventTypeKey, .input = *input_event};
|
|
||||||
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Выделение места под переменные плагина
|
|
||||||
*
|
|
||||||
* @return true Если всё прошло успешно
|
|
||||||
* @return false Если в процессе загрузки произошла ошибка
|
|
||||||
*/
|
|
||||||
static bool DHTMon_alloc(void) {
|
|
||||||
//Выделение места под данные плагина
|
|
||||||
app = malloc(sizeof(PluginData));
|
|
||||||
//Выделение места под очередь событий
|
|
||||||
app->event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
|
|
||||||
|
|
||||||
//Обнуление количества датчиков
|
|
||||||
app->sensors_count = -1;
|
|
||||||
|
|
||||||
//Инициализация мутекса
|
|
||||||
if(!init_mutex(&app->state_mutex, app, sizeof(PluginData))) {
|
|
||||||
FURI_LOG_E(APP_NAME, "cannot create mutex\r\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set system callbacks
|
|
||||||
app->view_port = view_port_alloc();
|
|
||||||
view_port_draw_callback_set(app->view_port, render_callback, &app->state_mutex);
|
|
||||||
view_port_input_callback_set(app->view_port, input_callback, app->event_queue);
|
|
||||||
|
|
||||||
// Open GUI and register view_port
|
|
||||||
app->gui = furi_record_open(RECORD_GUI);
|
|
||||||
gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen);
|
|
||||||
|
|
||||||
app->view_dispatcher = view_dispatcher_alloc();
|
|
||||||
|
|
||||||
sensorActions_sceneCreate(app);
|
|
||||||
sensorEdit_sceneCreate(app);
|
|
||||||
|
|
||||||
app->widget = widget_alloc();
|
|
||||||
view_dispatcher_add_view(app->view_dispatcher, WIDGET_VIEW, widget_get_view(app->widget));
|
|
||||||
|
|
||||||
app->text_input = text_input_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher, TEXTINPUT_VIEW, text_input_get_view(app->text_input));
|
|
||||||
|
|
||||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
|
||||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
|
||||||
|
|
||||||
//Уведомления
|
|
||||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
|
||||||
|
|
||||||
//Подготовка хранилища
|
|
||||||
app->storage = furi_record_open(RECORD_STORAGE);
|
|
||||||
storage_common_mkdir(app->storage, APP_PATH_FOLDER);
|
|
||||||
app->file_stream = file_stream_alloc(app->storage);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Освыбождение памяти после работы приложения
|
|
||||||
*/
|
|
||||||
static void DHTMon_free(void) {
|
|
||||||
//Автоматическое управление подсветкой
|
|
||||||
notification_message(app->notifications, &sequence_display_backlight_enforce_auto);
|
|
||||||
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
|
||||||
furi_record_close(RECORD_NOTIFICATION);
|
|
||||||
|
|
||||||
text_input_free(app->text_input);
|
|
||||||
widget_free(app->widget);
|
|
||||||
sensorEdit_sceneRemove();
|
|
||||||
sensorActions_screneRemove();
|
|
||||||
view_dispatcher_free(app->view_dispatcher);
|
|
||||||
|
|
||||||
furi_record_close(RECORD_GUI);
|
|
||||||
|
|
||||||
view_port_enabled_set(app->view_port, false);
|
|
||||||
gui_remove_view_port(app->gui, app->view_port);
|
|
||||||
|
|
||||||
view_port_free(app->view_port);
|
|
||||||
furi_message_queue_free(app->event_queue);
|
|
||||||
delete_mutex(&app->state_mutex);
|
|
||||||
|
|
||||||
free(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Точка входа в приложение
|
|
||||||
*
|
|
||||||
* @return Код ошибки
|
|
||||||
*/
|
|
||||||
int32_t quenon_dht_mon_app() {
|
|
||||||
if(!DHTMon_alloc()) {
|
|
||||||
DHTMon_free();
|
|
||||||
return 255;
|
|
||||||
}
|
|
||||||
//Постоянное свечение подсветки
|
|
||||||
notification_message(app->notifications, &sequence_display_backlight_enforce_on);
|
|
||||||
//Сохранение состояния наличия 5V на порту 1 FZ
|
|
||||||
app->last_OTG_State = furi_hal_power_is_otg_enabled();
|
|
||||||
|
|
||||||
//Загрузка датчиков с SD-карты
|
|
||||||
DHTMon_sensors_load();
|
|
||||||
|
|
||||||
app->currentSensorEdit = &app->sensors[0];
|
|
||||||
|
|
||||||
PluginEvent event;
|
|
||||||
for(bool processing = true; processing;) {
|
|
||||||
FuriStatus event_status = furi_message_queue_get(app->event_queue, &event, 100);
|
|
||||||
|
|
||||||
acquire_mutex_block(&app->state_mutex);
|
|
||||||
|
|
||||||
if(event_status == FuriStatusOk) {
|
|
||||||
// press events
|
|
||||||
if(event.type == EventTypeKey) {
|
|
||||||
if(event.input.type == InputTypePress) {
|
|
||||||
switch(event.input.key) {
|
|
||||||
case InputKeyUp:
|
|
||||||
break;
|
|
||||||
case InputKeyDown:
|
|
||||||
break;
|
|
||||||
case InputKeyRight:
|
|
||||||
break;
|
|
||||||
case InputKeyLeft:
|
|
||||||
break;
|
|
||||||
case InputKeyOk:
|
|
||||||
view_port_update(app->view_port);
|
|
||||||
release_mutex(&app->state_mutex, app);
|
|
||||||
mainMenu_scene(app);
|
|
||||||
break;
|
|
||||||
case InputKeyBack:
|
|
||||||
processing = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view_port_update(app->view_port);
|
|
||||||
release_mutex(&app->state_mutex, app);
|
|
||||||
}
|
|
||||||
//Освобождение памяти и деинициализация
|
|
||||||
DHTMon_sensors_deinit();
|
|
||||||
DHTMon_free();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
//TODO: Обработка ошибок
|
|
||||||
//TODO: Пропуск использованных портов в меню добавления датчиков
|
|
|
@ -1,176 +0,0 @@
|
||||||
#ifndef QUENON_DHT_MON
|
|
||||||
#define QUENON_DHT_MON
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
#include <furi_hal_power.h>
|
|
||||||
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <gui/modules/submenu.h>
|
|
||||||
#include <gui/modules/variable_item_list.h>
|
|
||||||
#include <gui/modules/text_input.h>
|
|
||||||
#include <gui/modules/widget.h>
|
|
||||||
#include <gui/view_dispatcher.h>
|
|
||||||
#include <gui/scene_manager.h>
|
|
||||||
|
|
||||||
#include <notification/notification.h>
|
|
||||||
#include <notification/notification_messages.h>
|
|
||||||
|
|
||||||
#include <toolbox/stream/file_stream.h>
|
|
||||||
#include <input/input.h>
|
|
||||||
|
|
||||||
#include "DHT.h"
|
|
||||||
|
|
||||||
#define APP_NAME "DHT_monitor"
|
|
||||||
#define APP_PATH_FOLDER "/ext/dht_monitor"
|
|
||||||
#define APP_FILENAME "sensors.txt"
|
|
||||||
#define MAX_SENSORS 5
|
|
||||||
|
|
||||||
// //Виды менюшек
|
|
||||||
typedef enum {
|
|
||||||
MAIN_MENU_VIEW,
|
|
||||||
ADDSENSOR_MENU_VIEW,
|
|
||||||
TEXTINPUT_VIEW,
|
|
||||||
SENSOR_ACTIONS_VIEW,
|
|
||||||
WIDGET_VIEW,
|
|
||||||
} MENU_VIEWS;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
EventTypeTick,
|
|
||||||
EventTypeKey,
|
|
||||||
} EventType;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
EventType type;
|
|
||||||
InputEvent input;
|
|
||||||
} PluginEvent;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const uint8_t num;
|
|
||||||
const char* name;
|
|
||||||
const GpioPin* pin;
|
|
||||||
} GpioItem;
|
|
||||||
|
|
||||||
//Структура с данными плагина
|
|
||||||
typedef struct {
|
|
||||||
//Очередь сообщений
|
|
||||||
FuriMessageQueue* event_queue;
|
|
||||||
//Мутекс
|
|
||||||
ValueMutex state_mutex;
|
|
||||||
//Вьюпорт
|
|
||||||
ViewPort* view_port;
|
|
||||||
//GUI
|
|
||||||
Gui* gui;
|
|
||||||
NotificationApp* notifications;
|
|
||||||
ViewDispatcher* view_dispatcher;
|
|
||||||
View* view;
|
|
||||||
TextInput* text_input;
|
|
||||||
VariableItem* item;
|
|
||||||
Widget* widget;
|
|
||||||
|
|
||||||
char txtbuff[30]; //Буффер для печати строк на экране
|
|
||||||
bool last_OTG_State; //Состояние OTG до запуска приложения
|
|
||||||
Storage* storage; //Хранилище датчиков
|
|
||||||
Stream* file_stream; //Поток файла с датчиками
|
|
||||||
int8_t sensors_count; // Количество загруженных датчиков
|
|
||||||
DHT_sensor sensors[MAX_SENSORS]; //Сохранённые датчики
|
|
||||||
DHT_data data; //Инфа из датчика
|
|
||||||
DHT_sensor* currentSensorEdit; //Указатель на редактируемый датчик
|
|
||||||
|
|
||||||
} PluginData;
|
|
||||||
|
|
||||||
/* ================== Работа с GPIO ================== */
|
|
||||||
/**
|
|
||||||
* @brief Конвертация GPIO в его номер на корпусе FZ
|
|
||||||
*
|
|
||||||
* @param gpio Указатель на преобразовываемый GPIO
|
|
||||||
* @return Номер порта на корпусе FZ
|
|
||||||
*/
|
|
||||||
uint8_t DHTMon_GPIO_to_int(const GpioPin* gpio);
|
|
||||||
/**
|
|
||||||
* @brief Конвертация номера порта на корпусе FZ в GPIO
|
|
||||||
*
|
|
||||||
* @param name Номер порта на корпусе FZ
|
|
||||||
* @return Указатель на GPIO при успехе, NULL при ошибке
|
|
||||||
*/
|
|
||||||
const GpioPin* DHTMon_GPIO_form_int(uint8_t name);
|
|
||||||
/**
|
|
||||||
* @brief Преобразование порядкового номера порта в GPIO
|
|
||||||
*
|
|
||||||
* @param index Индекс порта от 0 до GPIO_ITEMS-1
|
|
||||||
* @return Указатель на GPIO при успехе, NULL при ошибке
|
|
||||||
*/
|
|
||||||
const GpioPin* DHTMon_GPIO_from_index(uint8_t index);
|
|
||||||
/**
|
|
||||||
* @brief Преобразование GPIO в порядковый номер порта
|
|
||||||
*
|
|
||||||
* @param gpio Указатель на GPIO
|
|
||||||
* @return index при успехе, 255 при ошибке
|
|
||||||
*/
|
|
||||||
uint8_t DHTMon_GPIO_to_index(const GpioPin* gpio);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Получить имя GPIO в виде строки
|
|
||||||
*
|
|
||||||
* @param gpio Искомый порт
|
|
||||||
* @return char* Указатель на строку с именем порта
|
|
||||||
*/
|
|
||||||
const char* DHTMon_GPIO_getName(const GpioPin* gpio);
|
|
||||||
|
|
||||||
/* ================== Работа с датчиками ================== */
|
|
||||||
/**
|
|
||||||
* @brief Инициализация портов ввода/вывода датчиков
|
|
||||||
*/
|
|
||||||
void DHTMon_sensors_init(void);
|
|
||||||
/**
|
|
||||||
* @brief Функция деинициализации портов ввода/вывода датчиков
|
|
||||||
*/
|
|
||||||
void DHTMon_sensors_deinit(void);
|
|
||||||
/**
|
|
||||||
* @brief Проверка корректности параметров датчика
|
|
||||||
*
|
|
||||||
* @param sensor Указатель на проверяемый датчик
|
|
||||||
* @return true Параметры датчика корректные
|
|
||||||
* @return false Параметры датчика некорректные
|
|
||||||
*/
|
|
||||||
bool DHTMon_sensor_check(DHT_sensor* sensor);
|
|
||||||
/**
|
|
||||||
* @brief Удаление датчика из списка и перезагрузка
|
|
||||||
*
|
|
||||||
* @param sensor Указатель на удаляемый датчик
|
|
||||||
*/
|
|
||||||
void DHTMon_sensor_delete(DHT_sensor* sensor);
|
|
||||||
/**
|
|
||||||
* @brief Сохранение датчиков на SD-карту
|
|
||||||
*
|
|
||||||
* @return Количество сохранённых датчиков
|
|
||||||
*/
|
|
||||||
uint8_t DHTMon_sensors_save(void);
|
|
||||||
/**
|
|
||||||
* @brief Загрузка датчиков с SD-карты
|
|
||||||
*
|
|
||||||
* @return true Был загружен хотя бы 1 датчик
|
|
||||||
* @return false Датчики отсутствуют
|
|
||||||
*/
|
|
||||||
bool DHTMon_sensors_load(void);
|
|
||||||
/**
|
|
||||||
* @brief Перезагрузка датчиков с SD-карты
|
|
||||||
*
|
|
||||||
* @return true Когда был загружен хотя бы 1 датчик
|
|
||||||
* @return false Ни один из датчиков не был загружен
|
|
||||||
*/
|
|
||||||
bool DHTMon_sensors_reload(void);
|
|
||||||
|
|
||||||
void scene_main(Canvas* const canvas, PluginData* app);
|
|
||||||
void mainMenu_scene(PluginData* app);
|
|
||||||
|
|
||||||
void sensorEdit_sceneCreate(PluginData* app);
|
|
||||||
void sensorEdit_scene(PluginData* app);
|
|
||||||
void sensorEdit_sceneRemove(void);
|
|
||||||
|
|
||||||
void sensorActions_sceneCreate(PluginData* app);
|
|
||||||
void sensorActions_scene(PluginData* app);
|
|
||||||
void sensorActions_screneRemove(void);
|
|
||||||
#endif
|
|
|
@ -1,157 +0,0 @@
|
||||||
#include "../quenon_dht_mon.h"
|
|
||||||
//Текущий вид
|
|
||||||
static View* view;
|
|
||||||
//Список
|
|
||||||
static VariableItemList* variable_item_list;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Функция обработки нажатия кнопки "Назад"
|
|
||||||
*
|
|
||||||
* @param context Указатель на данные приложения
|
|
||||||
* @return ID вида в который нужно переключиться
|
|
||||||
*/
|
|
||||||
static uint32_t actions_exitCallback(void* context) {
|
|
||||||
PluginData* app = context;
|
|
||||||
UNUSED(app);
|
|
||||||
//Возвращаем ID вида, в который нужно вернуться
|
|
||||||
return VIEW_NONE;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief Функция обработки нажатия средней кнопки
|
|
||||||
*
|
|
||||||
* @param context Указатель на данные приложения
|
|
||||||
* @param index На каком элементе списка была нажата кнопка
|
|
||||||
*/
|
|
||||||
static void enterCallback(void* context, uint32_t index) {
|
|
||||||
PluginData* app = context;
|
|
||||||
if((uint8_t)index < (uint8_t)app->sensors_count) {
|
|
||||||
app->currentSensorEdit = &app->sensors[index];
|
|
||||||
sensorActions_scene(app);
|
|
||||||
}
|
|
||||||
if((uint8_t)index == (uint8_t)app->sensors_count) {
|
|
||||||
app->currentSensorEdit = &app->sensors[app->sensors_count++];
|
|
||||||
strcpy(app->currentSensorEdit->name, "NewSensor");
|
|
||||||
app->currentSensorEdit->GPIO = DHTMon_GPIO_from_index(0);
|
|
||||||
app->currentSensorEdit->type = DHT11;
|
|
||||||
sensorEdit_scene(app);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Создание списка действий с указанным датчиком
|
|
||||||
*
|
|
||||||
* @param app Указатель на данные плагина
|
|
||||||
*/
|
|
||||||
void mainMenu_scene(PluginData* app) {
|
|
||||||
variable_item_list = variable_item_list_alloc();
|
|
||||||
//Сброс всех элементов меню
|
|
||||||
variable_item_list_reset(variable_item_list);
|
|
||||||
//Добавление названий датчиков в качестве элементов списка
|
|
||||||
for(uint8_t i = 0; i < app->sensors_count; i++) {
|
|
||||||
variable_item_list_add(variable_item_list, app->sensors[i].name, 1, NULL, NULL);
|
|
||||||
}
|
|
||||||
if(app->sensors_count < (uint8_t)MAX_SENSORS) {
|
|
||||||
variable_item_list_add(variable_item_list, " + Add new sensor +", 1, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Добавление колбека на нажатие средней кнопки
|
|
||||||
variable_item_list_set_enter_callback(variable_item_list, enterCallback, app);
|
|
||||||
|
|
||||||
//Создание вида из списка
|
|
||||||
view = variable_item_list_get_view(variable_item_list);
|
|
||||||
//Добавление колбека на нажатие кнопки "Назад"
|
|
||||||
view_set_previous_callback(view, actions_exitCallback);
|
|
||||||
//Добавление вида в диспетчер
|
|
||||||
view_dispatcher_add_view(app->view_dispatcher, MAIN_MENU_VIEW, view);
|
|
||||||
|
|
||||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
|
||||||
|
|
||||||
//Переключение на наш вид
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, MAIN_MENU_VIEW);
|
|
||||||
|
|
||||||
//Запуск диспетчера
|
|
||||||
view_dispatcher_run(app->view_dispatcher);
|
|
||||||
|
|
||||||
//Очистка списка элементов
|
|
||||||
variable_item_list_free(variable_item_list);
|
|
||||||
//Удаление вида после обработки
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, MAIN_MENU_VIEW);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
// static VariableItemList* variable_item_list;
|
|
||||||
// /* ============== Главное меню ============== */
|
|
||||||
// static uint32_t mainMenu_exitCallback(void* context) {
|
|
||||||
// UNUSED(context);
|
|
||||||
// variable_item_list_free(variable_item_list);
|
|
||||||
// DHT_sensors_reload();
|
|
||||||
// return VIEW_NONE;
|
|
||||||
// }
|
|
||||||
// static void mainMenu_enterCallback(void* context, uint32_t index) {
|
|
||||||
// PluginData* app = context;
|
|
||||||
// if((uint8_t)index == (uint8_t)app->sensors_count) {
|
|
||||||
// addSensor_scene(app);
|
|
||||||
// view_dispatcher_run(app->view_dispatcher);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// void mainMenu_scene(PluginData* app) {
|
|
||||||
// variable_item_list = variable_item_list_alloc();
|
|
||||||
// variable_item_list_reset(variable_item_list);
|
|
||||||
// for(uint8_t i = 0; i < app->sensors_count; i++) {
|
|
||||||
// variable_item_list_add(variable_item_list, app->sensors[i].name, 1, NULL, NULL);
|
|
||||||
// }
|
|
||||||
// variable_item_list_add(variable_item_list, "+ Add new sensor +", 1, NULL, NULL);
|
|
||||||
|
|
||||||
// app->view = variable_item_list_get_view(variable_item_list);
|
|
||||||
// app->view_dispatcher = view_dispatcher_alloc();
|
|
||||||
|
|
||||||
// view_dispatcher_enable_queue(app->view_dispatcher);
|
|
||||||
// view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
|
||||||
// view_dispatcher_add_view(app->view_dispatcher, MAIN_MENU_VIEW, app->view);
|
|
||||||
// view_dispatcher_switch_to_view(app->view_dispatcher, MAIN_MENU_VIEW);
|
|
||||||
|
|
||||||
// variable_item_list_set_enter_callback(variable_item_list, mainMenu_enterCallback, app);
|
|
||||||
// view_set_previous_callback(app->view, mainMenu_exitCallback);
|
|
||||||
// }
|
|
|
@ -1,40 +0,0 @@
|
||||||
#include "../quenon_dht_mon.h"
|
|
||||||
|
|
||||||
/* ============== Главный экран ============== */
|
|
||||||
void scene_main(Canvas* const canvas, PluginData* app) {
|
|
||||||
//Рисование бара
|
|
||||||
canvas_draw_box(canvas, 0, 0, 128, 14);
|
|
||||||
canvas_set_color(canvas, ColorWhite);
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_str(canvas, 32, 11, "DHT Monitor");
|
|
||||||
|
|
||||||
canvas_set_color(canvas, ColorBlack);
|
|
||||||
if(app->sensors_count > 0) {
|
|
||||||
if(!furi_hal_power_is_otg_enabled()) {
|
|
||||||
furi_hal_power_enable_otg();
|
|
||||||
}
|
|
||||||
for(uint8_t i = 0; i < app->sensors_count; i++) {
|
|
||||||
app->data = DHT_getData(&app->sensors[i]);
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_str(canvas, 0, 24 + 10 * i, app->sensors[i].name);
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
if(app->data.hum == -128.0f && app->data.temp == -128.0f) {
|
|
||||||
canvas_draw_str(canvas, 96, 24 + 10 * i, "timeout");
|
|
||||||
} else {
|
|
||||||
snprintf(
|
|
||||||
app->txtbuff,
|
|
||||||
sizeof(app->txtbuff),
|
|
||||||
"%2.1f*C/%d%%",
|
|
||||||
(double)app->data.temp,
|
|
||||||
(int8_t)app->data.hum);
|
|
||||||
canvas_draw_str(canvas, 64, 24 + 10 * i, app->txtbuff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
if(app->sensors_count == 0) canvas_draw_str(canvas, 0, 24, "Sensors not found");
|
|
||||||
if(app->sensors_count == -1) canvas_draw_str(canvas, 0, 24, "Loading...");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,194 +0,0 @@
|
||||||
#include "../quenon_dht_mon.h"
|
|
||||||
|
|
||||||
//Текущий вид
|
|
||||||
static View* view;
|
|
||||||
//Список
|
|
||||||
static VariableItemList* variable_item_list;
|
|
||||||
|
|
||||||
/* ================== Информация о датчике ================== */
|
|
||||||
/**
|
|
||||||
* @brief Функция обработки нажатия кнопки "Назад"
|
|
||||||
*
|
|
||||||
* @param context Указатель на данные приложения
|
|
||||||
* @return ID вида в который нужно переключиться
|
|
||||||
*/
|
|
||||||
static uint32_t infoWidget_exitCallback(void* context) {
|
|
||||||
PluginData* app = context;
|
|
||||||
UNUSED(app);
|
|
||||||
//Возвращаем ID вида, в который нужно вернуться
|
|
||||||
return SENSOR_ACTIONS_VIEW;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief Обработчик нажатий на кнопку в виджете
|
|
||||||
*
|
|
||||||
* @param result Какая из кнопок была нажата
|
|
||||||
* @param type Тип нажатия
|
|
||||||
* @param context Указатель на данные плагина
|
|
||||||
*/
|
|
||||||
static void infoWidget_callback(GuiButtonType result, InputType type, void* context) {
|
|
||||||
PluginData* app = context;
|
|
||||||
//Коротко нажата левая кнопка (Back)
|
|
||||||
if(result == GuiButtonTypeLeft && type == InputTypeShort) {
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, SENSOR_ACTIONS_VIEW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief Создание виджета информации о датчике
|
|
||||||
*
|
|
||||||
* @param app Указатель на данные плагина
|
|
||||||
*/
|
|
||||||
static void sensorInfo_widget(PluginData* app) {
|
|
||||||
//Очистка виджета
|
|
||||||
widget_reset(app->widget);
|
|
||||||
//Добавление кнопок
|
|
||||||
widget_add_button_element(app->widget, GuiButtonTypeLeft, "Back", infoWidget_callback, app);
|
|
||||||
|
|
||||||
char str[32];
|
|
||||||
snprintf(str, sizeof(str), "\e#%s\e#", app->currentSensorEdit->name);
|
|
||||||
widget_add_text_box_element(app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, str, false);
|
|
||||||
snprintf(str, sizeof(str), "\e#Type:\e# %s", app->currentSensorEdit->type ? "DHT22" : "DHT11");
|
|
||||||
widget_add_text_box_element(app->widget, 0, 0, 128, 47, AlignLeft, AlignCenter, str, false);
|
|
||||||
snprintf(
|
|
||||||
str, sizeof(str), "\e#GPIO:\e# %s", DHTMon_GPIO_getName(app->currentSensorEdit->GPIO));
|
|
||||||
widget_add_text_box_element(app->widget, 0, 0, 128, 72, AlignLeft, AlignCenter, str, false);
|
|
||||||
view_set_previous_callback(widget_get_view(app->widget), infoWidget_exitCallback);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, WIDGET_VIEW);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================== Подтверждение удаления ================== */
|
|
||||||
/**
|
|
||||||
* @brief Функция обработки нажатия кнопки "Назад"
|
|
||||||
*
|
|
||||||
* @param context Указатель на данные приложения
|
|
||||||
* @return ID вида в который нужно переключиться
|
|
||||||
*/
|
|
||||||
static uint32_t deleteWidget_exitCallback(void* context) {
|
|
||||||
PluginData* app = context;
|
|
||||||
UNUSED(app);
|
|
||||||
//Возвращаем ID вида, в который нужно вернуться
|
|
||||||
return SENSOR_ACTIONS_VIEW;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief Обработчик нажатий на кнопку в виджете
|
|
||||||
*
|
|
||||||
* @param result Какая из кнопок была нажата
|
|
||||||
* @param type Тип нажатия
|
|
||||||
* @param context Указатель на данные плагина
|
|
||||||
*/
|
|
||||||
static void deleteWidget_callback(GuiButtonType result, InputType type, void* context) {
|
|
||||||
PluginData* app = context;
|
|
||||||
//Коротко нажата левая кнопка (Cancel)
|
|
||||||
if(result == GuiButtonTypeLeft && type == InputTypeShort) {
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, SENSOR_ACTIONS_VIEW);
|
|
||||||
}
|
|
||||||
//Коротко нажата правая кнопка (Delete)
|
|
||||||
if(result == GuiButtonTypeRight && type == InputTypeShort) {
|
|
||||||
//Удаление датчика
|
|
||||||
DHTMon_sensor_delete(app->currentSensorEdit);
|
|
||||||
//Выход из меню
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_NONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief Создание виджета удаления датчика
|
|
||||||
*
|
|
||||||
* @param app Указатель на данные плагина
|
|
||||||
*/
|
|
||||||
static void sensorDelete_widget(PluginData* app) {
|
|
||||||
//Очистка виджета
|
|
||||||
widget_reset(app->widget);
|
|
||||||
//Добавление кнопок
|
|
||||||
widget_add_button_element(
|
|
||||||
app->widget, GuiButtonTypeLeft, "Cancel", deleteWidget_callback, app);
|
|
||||||
widget_add_button_element(
|
|
||||||
app->widget, GuiButtonTypeRight, "Delete", deleteWidget_callback, app);
|
|
||||||
|
|
||||||
char delete_str[32];
|
|
||||||
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", app->currentSensorEdit->name);
|
|
||||||
widget_add_text_box_element(
|
|
||||||
app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str, false);
|
|
||||||
snprintf(
|
|
||||||
delete_str,
|
|
||||||
sizeof(delete_str),
|
|
||||||
"\e#Type:\e# %s",
|
|
||||||
app->currentSensorEdit->type ? "DHT22" : "DHT11");
|
|
||||||
widget_add_text_box_element(
|
|
||||||
app->widget, 0, 0, 128, 47, AlignLeft, AlignCenter, delete_str, false);
|
|
||||||
snprintf(
|
|
||||||
delete_str,
|
|
||||||
sizeof(delete_str),
|
|
||||||
"\e#GPIO:\e# %s",
|
|
||||||
DHTMon_GPIO_getName(app->currentSensorEdit->GPIO));
|
|
||||||
widget_add_text_box_element(
|
|
||||||
app->widget, 0, 0, 128, 72, AlignLeft, AlignCenter, delete_str, false);
|
|
||||||
view_set_previous_callback(widget_get_view(app->widget), deleteWidget_exitCallback);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, WIDGET_VIEW);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================== Меню действий ================== */
|
|
||||||
/**
|
|
||||||
* @brief Функция обработки нажатия средней кнопки
|
|
||||||
*
|
|
||||||
* @param context Указатель на данные приложения
|
|
||||||
* @param index На каком элементе списка была нажата кнопка
|
|
||||||
*/
|
|
||||||
static void enterCallback(void* context, uint32_t index) {
|
|
||||||
PluginData* app = context;
|
|
||||||
if(index == 0) {
|
|
||||||
sensorInfo_widget(app);
|
|
||||||
}
|
|
||||||
if(index == 1) {
|
|
||||||
sensorEdit_scene(app);
|
|
||||||
}
|
|
||||||
if(index == 2) {
|
|
||||||
sensorDelete_widget(app);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Функция обработки нажатия кнопки "Назад"
|
|
||||||
*
|
|
||||||
* @param context Указатель на данные приложения
|
|
||||||
* @return ID вида в который нужно переключиться
|
|
||||||
*/
|
|
||||||
static uint32_t actions_exitCallback(void* context) {
|
|
||||||
PluginData* app = context;
|
|
||||||
UNUSED(app);
|
|
||||||
//Возвращаем ID вида, в который нужно вернуться
|
|
||||||
return MAIN_MENU_VIEW;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Создание списка действий с указанным датчиком
|
|
||||||
*
|
|
||||||
* @param app Указатель на данные плагина
|
|
||||||
*/
|
|
||||||
void sensorActions_sceneCreate(PluginData* app) {
|
|
||||||
variable_item_list = variable_item_list_alloc();
|
|
||||||
//Сброс всех элементов меню
|
|
||||||
variable_item_list_reset(variable_item_list);
|
|
||||||
//Добавление элементов в список
|
|
||||||
variable_item_list_add(variable_item_list, "Info", 0, NULL, NULL);
|
|
||||||
variable_item_list_add(variable_item_list, "Edit", 0, NULL, NULL);
|
|
||||||
variable_item_list_add(variable_item_list, "Delete", 0, NULL, NULL);
|
|
||||||
|
|
||||||
//Добавление колбека на нажатие средней кнопки
|
|
||||||
variable_item_list_set_enter_callback(variable_item_list, enterCallback, app);
|
|
||||||
|
|
||||||
//Создание вида из списка
|
|
||||||
view = variable_item_list_get_view(variable_item_list);
|
|
||||||
//Добавление колбека на нажатие кнопки "Назад"
|
|
||||||
view_set_previous_callback(view, actions_exitCallback);
|
|
||||||
//Добавление вида в диспетчер
|
|
||||||
view_dispatcher_add_view(app->view_dispatcher, SENSOR_ACTIONS_VIEW, view);
|
|
||||||
}
|
|
||||||
void sensorActions_scene(PluginData* app) {
|
|
||||||
//Сброс выбранного пункта в ноль
|
|
||||||
variable_item_list_set_selected_item(variable_item_list, 0);
|
|
||||||
//Переключение на наш вид
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, SENSOR_ACTIONS_VIEW);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sensorActions_screneRemove(void) {
|
|
||||||
variable_item_list_free(variable_item_list);
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
#include "../quenon_dht_mon.h"
|
|
||||||
|
|
||||||
static VariableItem* nameItem;
|
|
||||||
static VariableItemList* variable_item_list;
|
|
||||||
|
|
||||||
static const char* const sensorsTypes[2] = {
|
|
||||||
"DHT11",
|
|
||||||
"DHT22",
|
|
||||||
};
|
|
||||||
|
|
||||||
// /* ============== Добавление датчика ============== */
|
|
||||||
static uint32_t addSensor_exitCallback(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
DHTMon_sensors_reload();
|
|
||||||
return VIEW_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addSensor_sensorTypeChanged(VariableItem* item) {
|
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
|
||||||
PluginData* app = variable_item_get_context(item);
|
|
||||||
variable_item_set_current_value_text(item, sensorsTypes[index]);
|
|
||||||
app->currentSensorEdit->type = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addSensor_GPIOChanged(VariableItem* item) {
|
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
|
||||||
variable_item_set_current_value_text(item, DHTMon_GPIO_getName(DHTMon_GPIO_from_index(index)));
|
|
||||||
PluginData* app = variable_item_get_context(item);
|
|
||||||
app->currentSensorEdit->GPIO = DHTMon_GPIO_from_index(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addSensor_sensorNameChanged(void* context) {
|
|
||||||
PluginData* app = context;
|
|
||||||
variable_item_set_current_value_text(nameItem, app->currentSensorEdit->name);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, ADDSENSOR_MENU_VIEW);
|
|
||||||
}
|
|
||||||
static void addSensor_sensorNameChange(PluginData* app) {
|
|
||||||
text_input_set_header_text(app->text_input, "Sensor name");
|
|
||||||
//По неясной мне причине в длину строки входит терминатор. Поэтому при длине 10 приходится указывать 11
|
|
||||||
text_input_set_result_callback(
|
|
||||||
app->text_input, addSensor_sensorNameChanged, app, app->currentSensorEdit->name, 11, true);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, TEXTINPUT_VIEW);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addSensor_enterCallback(void* context, uint32_t index) {
|
|
||||||
PluginData* app = context;
|
|
||||||
if(index == 0) {
|
|
||||||
addSensor_sensorNameChange(app);
|
|
||||||
}
|
|
||||||
if(index == 3) {
|
|
||||||
//Сохранение датчика
|
|
||||||
DHTMon_sensors_save();
|
|
||||||
DHTMon_sensors_reload();
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_NONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sensorEdit_sceneCreate(PluginData* app) {
|
|
||||||
variable_item_list = variable_item_list_alloc();
|
|
||||||
|
|
||||||
variable_item_list_reset(variable_item_list);
|
|
||||||
|
|
||||||
variable_item_list_set_enter_callback(variable_item_list, addSensor_enterCallback, app);
|
|
||||||
|
|
||||||
app->view = variable_item_list_get_view(variable_item_list);
|
|
||||||
|
|
||||||
view_set_previous_callback(app->view, addSensor_exitCallback);
|
|
||||||
|
|
||||||
view_dispatcher_add_view(app->view_dispatcher, ADDSENSOR_MENU_VIEW, app->view);
|
|
||||||
}
|
|
||||||
void sensorEdit_scene(PluginData* app) {
|
|
||||||
//Очистка списка
|
|
||||||
variable_item_list_reset(variable_item_list);
|
|
||||||
|
|
||||||
//Имя редактируемого датчика
|
|
||||||
nameItem = variable_item_list_add(variable_item_list, "Name: ", 1, NULL, NULL);
|
|
||||||
variable_item_set_current_value_index(nameItem, 0);
|
|
||||||
variable_item_set_current_value_text(nameItem, app->currentSensorEdit->name);
|
|
||||||
|
|
||||||
//Тип датчика
|
|
||||||
app->item =
|
|
||||||
variable_item_list_add(variable_item_list, "Type:", 2, addSensor_sensorTypeChanged, app);
|
|
||||||
|
|
||||||
variable_item_set_current_value_index(app->item, app->currentSensorEdit->type);
|
|
||||||
variable_item_set_current_value_text(app->item, sensorsTypes[app->currentSensorEdit->type]);
|
|
||||||
|
|
||||||
//GPIO
|
|
||||||
app->item =
|
|
||||||
variable_item_list_add(variable_item_list, "GPIO:", 13, addSensor_GPIOChanged, app);
|
|
||||||
variable_item_set_current_value_index(
|
|
||||||
app->item, DHTMon_GPIO_to_index(app->currentSensorEdit->GPIO));
|
|
||||||
variable_item_set_current_value_text(
|
|
||||||
app->item, DHTMon_GPIO_getName(app->currentSensorEdit->GPIO));
|
|
||||||
variable_item_list_add(variable_item_list, "Save", 1, NULL, app);
|
|
||||||
|
|
||||||
//Сброс выбранного пункта в ноль
|
|
||||||
variable_item_list_set_selected_item(variable_item_list, 0);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, ADDSENSOR_MENU_VIEW);
|
|
||||||
}
|
|
||||||
void sensorEdit_sceneRemove(void) {
|
|
||||||
variable_item_list_free(variable_item_list);
|
|
||||||
}
|
|
Loading…
Reference in a new issue