Przeglądaj źródła

Update sensors API

Victor 3 lat temu
rodzic
commit
1dbe2dded6
6 zmienionych plików z 752 dodań i 3 usunięć
  1. 289 0
      Sensors.c
  2. 169 0
      Sensors.h
  3. 223 0
      interfaces/OneWireSensor.c
  4. 68 0
      interfaces/OneWireSensor.h
  5. 2 2
      unitemp.c
  6. 1 1
      unitemp.h

+ 289 - 0
Sensors.c

@@ -0,0 +1,289 @@
+#include "Sensors.h"
+#include "./interfaces/OneWireSensor.h"
+
+#include <furi_hal_power.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(GPIOList) / sizeof(GPIO))
+
+//Перечень достуных портов ввода/вывода
+//static
+const GPIO GPIOList[] = {
+    {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 const char* sensorNames[SENSOR_TYPES_COUNT] = {
+    "DHT11",
+    "DHT12 (1 Wire)",
+    "DHT12 (I2C)",
+    "DHT20",
+    "DHT21", //AM2301
+    "DHT22", //AM2302
+    "AM2320 (1W)",
+    "AM2320 (I2C)",
+    "LM75",
+    "DS18B20",
+    "BMP180",
+    "BMP280",
+    "BME280",
+};
+
+const char* unitemp_getSensorTypeName(SensorType st) {
+    if(st >= SENSOR_TYPES_COUNT) return NULL;
+    return sensorNames[st];
+}
+
+const GPIO* unitemp_GPIO_getFromInt(uint8_t name) {
+    for(uint8_t i = 0; i < GPIO_ITEMS; i++) {
+        if(GPIOList[i].num == name) {
+            return &GPIOList[i];
+        }
+    }
+    return NULL;
+}
+
+uint8_t unitemp_GPIO_toInt(const GpioPin* gpio) {
+    if(gpio == NULL) return 255;
+    for(uint8_t i = 0; i < GPIO_ITEMS; i++) {
+        if(GPIOList[i].pin->pin == gpio->pin && GPIOList[i].pin->port == gpio->port) {
+            return GPIOList[i].num;
+        }
+    }
+    return 255;
+}
+
+bool unitemp_sensors_load() {
+    FURI_LOG_D(APP_NAME, "Loading sensors...");
+    app->sensors_count = 0;
+    memset(app->sensors, 0, sizeof(app->sensors));
+
+    //Выделение памяти на поток
+    app->file_stream = file_stream_alloc(app->storage);
+
+    //Переменная пути к файлу
+    char filepath[sizeof(APP_PATH_FOLDER) + sizeof(APP_FILENAME_SENSORS)] = {0};
+    //Составление пути к файлу
+    strcpy(filepath, APP_PATH_FOLDER);
+    strcat(filepath, "/");
+    strcat(filepath, APP_FILENAME_SENSORS);
+
+    //Открытие потока к файлу с датчиками
+    if(!file_stream_open(app->file_stream, filepath, FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) {
+        if(file_stream_get_error(app->file_stream) == FSE_NOT_EXIST) {
+            FURI_LOG_W(APP_NAME, "Missing sensors file");
+            //Закрытие потока и освобождение памяти
+            file_stream_close(app->file_stream);
+            stream_free(app->file_stream);
+            return false;
+        } else {
+            FURI_LOG_E(
+                APP_NAME,
+                "An error occurred while loading the sensors file: %d",
+                file_stream_get_error(app->file_stream));
+            //Закрытие потока и освобождение памяти
+            file_stream_close(app->file_stream);
+            stream_free(app->file_stream);
+            return false;
+        }
+    }
+
+    //Вычисление размера файла
+    size_t file_size = stream_size(app->file_stream);
+    FURI_LOG_D(APP_NAME, "Sensors file size: %d bytes", file_size);
+    //Если файл пустой, то:
+    if(file_size == (size_t)0) {
+        FURI_LOG_W(APP_NAME, "Sensors file is empty");
+        //Закрытие потока и освобождение памяти
+        file_stream_close(app->file_stream);
+        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 sensors file");
+        //Закрытие потока и освобождение памяти
+        file_stream_close(app->file_stream);
+        stream_free(app->file_stream);
+        free(file_buf);
+        return false;
+    }
+
+    //Построчное чтение файла
+    char* line = strtok((char*)file_buf, "\n");
+    while(line != NULL) {
+        char name[11] = {0};
+        int type = 255, otherValue = 255;
+        sscanf(line, "%s %d %d", name, &type, &otherValue);
+        //Ограничение длины имени
+        name[10] = '\0';
+        FURI_LOG_D(APP_NAME, "%s %d %d", name, type, otherValue);
+        //Проверка типа датчика
+        if(type < SENSOR_TYPES_COUNT && sizeof(name) <= 11) {
+            app->sensors[app->sensors_count] = unitemp_sensor_alloc(name, type);
+            if(app->sensors[app->sensors_count]->interface == ONE_WIRE) {
+                if(unitemp_GPIO_getFromInt(otherValue) != NULL) {
+                    unitemp_oneWire_sensorSetGPIO(
+                        app->sensors[app->sensors_count], unitemp_GPIO_getFromInt(otherValue));
+                    //Сохранение датчика если всё ок
+                    app->sensors_count++;
+                }
+            }
+        }
+        line = strtok((char*)NULL, "\n");
+    }
+    free(file_buf);
+    file_stream_close(app->file_stream);
+    stream_free(app->file_stream);
+
+    FURI_LOG_I(APP_NAME, "Sensors have been successfully loaded");
+    return true;
+}
+
+bool unitemp_sensors_save(void) {
+    FURI_LOG_D(APP_NAME, "Saving sensors...");
+
+    //Выделение памяти для потока
+    app->file_stream = file_stream_alloc(app->storage);
+
+    //Переменная пути к файлу
+    char filepath[sizeof(APP_PATH_FOLDER) + sizeof(APP_FILENAME_SENSORS)] = {0};
+    //Составление пути к файлу
+    strcpy(filepath, APP_PATH_FOLDER);
+    strcat(filepath, "/");
+    strcat(filepath, APP_FILENAME_SENSORS);
+    //Создание папки плагина
+    storage_common_mkdir(app->storage, APP_PATH_FOLDER);
+    //Открытие потока
+    if(!file_stream_open(app->file_stream, filepath, FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)) {
+        FURI_LOG_E(
+            APP_NAME,
+            "An error occurred while saving the sensors file: %d",
+            file_stream_get_error(app->file_stream));
+        //Закрытие потока и освобождение памяти
+        file_stream_close(app->file_stream);
+        stream_free(app->file_stream);
+        return false;
+    }
+
+    //Сохранение датчиков
+    for(size_t i = 0; i < app->sensors_count; i++) {
+        if(app->sensors[i]->interface == ONE_WIRE) {
+            stream_write_format(
+                app->file_stream,
+                "%s %d %d\n",
+                app->sensors[i]->name,
+                app->sensors[i]->type,
+                unitemp_GPIO_toInt(unitemp_oneWire_sensorGetGPIO(app->sensors[i])->pin));
+        }
+    }
+
+    //Закрытие потока и освобождение памяти
+    file_stream_close(app->file_stream);
+    stream_free(app->file_stream);
+
+    FURI_LOG_I(APP_NAME, "Sensors have been successfully saved");
+    return true;
+}
+
+Sensor* unitemp_sensor_alloc(char* name, SensorType st) {
+    //Выделение памяти под датчик
+    Sensor* sensor = malloc(sizeof(Sensor));
+    if(sensor == NULL) return false;
+    sensor->name = malloc(11);
+    strcpy(sensor->name, name);
+    sensor->status = UT_ERROR;
+
+    //Выделение памяти под инстанс датчиков One Wire
+    if(st == DHT11 || st == DHT12_1W || st == DHT21 || st == DHT22 || st == AM2320_1W) {
+        unitemp_oneWire_sensorAlloc(sensor, st);
+    }
+    return sensor;
+}
+
+bool unitemp_sensors_init(void) {
+    bool result = true;
+
+    //Перебор датчиков из списка
+    for(size_t i = 0; i < app->sensors_count; i++) {
+        //Включение 5V если на порту 1 FZ его нет
+        //Может пропасть при отключении USB
+        if(furi_hal_power_is_otg_enabled() != true) {
+            furi_hal_power_enable_otg();
+            FURI_LOG_D(APP_NAME, "OTG enabled");
+        }
+        if(!(*app->sensors[i]->initializer)(app->sensors[i])) {
+            FURI_LOG_E(
+                APP_NAME,
+                "An error occurred during sensor initialization %s",
+                app->sensors[i]->name);
+            result = false;
+        }
+    }
+    return result;
+}
+
+bool unitemp_sensors_deInit(void) {
+    bool result = true;
+    //Выключение 5 В если до этого оно не было включено
+    if(app->settings.lastOTGState != true) {
+        furi_hal_power_disable_otg();
+        FURI_LOG_D(APP_NAME, "OTG disabled");
+    }
+
+    //Перебор датчиков из списка
+    for(size_t i = 0; i < app->sensors_count; i++) {
+        if(!(*app->sensors[i]->deinitializer)(app->sensors[i])) {
+            FURI_LOG_E(
+                APP_NAME,
+                "An error occurred during sensor deinitialization %s",
+                app->sensors[i]->name);
+            result = false;
+        }
+        free(app->sensors[i]);
+    }
+    return result;
+}
+
+UnitempStatus unitemp_sensor_updateData(Sensor* sensor) {
+    if(sensor == NULL) return UT_ERROR;
+
+    if(!furi_hal_power_is_otg_enabled()) {
+        furi_hal_power_enable_otg();
+    }
+
+    sensor->status = sensor->updater(sensor);
+    if(app->settings.unit == FAHRENHEIT) uintemp_celsiumToFarengate(sensor);
+    return sensor->status;
+
+    sensor->status = UT_ERROR;
+    return sensor->status;
+}
+
+void unitemp_sensors_updateValues(void) {
+    for(size_t i = 0; i < app->sensors_count; i++) {
+        unitemp_sensor_updateData(app->sensors[i]);
+    }
+}

+ 169 - 0
Sensors.h

@@ -0,0 +1,169 @@
+#ifndef UNITEMP_SENSORS
+#define UNITEMP_SENSORS
+#include <furi.h>
+#include <input/input.h>
+
+//Статусы опроса датчика
+typedef enum {
+    UT_OK, //Всё хорошо, опрос успешен
+    UT_TIMEOUT, //Датчик не отозвался
+    UT_EARLYPOOL, //Опрос раньше положенной задержки
+    UT_BADCRC, //Неверная контрольная сумма
+    UT_ERROR, //Прочие ошибки
+} UnitempStatus;
+
+//Типы датчиков
+typedef enum {
+    DHT11,
+    DHT12_1W,
+    DHT12_I2C,
+    DHT20, //AM2108
+    DHT21, //AM2301
+    DHT22, //AM2302
+    AM2320_1W,
+    AM2320_I2C,
+    LM75,
+    DS18B20,
+    BMP180,
+    BMP280,
+    BME280,
+
+    //Порядок сенсоров сверху не менять!
+    SENSOR_TYPES_COUNT //Общее количество типов датчиков
+} SensorType;
+
+//Типы подключения датчиков
+typedef enum Interface {
+    ONE_WIRE, //Собственный однопроводной протокол датчиков DHTXX и AM23XX
+    DALLAS, //Однопроводной протокол Dallas
+    I2C,
+    SPI,
+
+    CONNECTION_TYPES_COUNT //Общее количество типов подключений
+} Interface;
+
+//Порт ввода/вывода Flipper Zero
+typedef struct GPIO {
+    const uint8_t num;
+    const char* name;
+    const GpioPin* pin;
+} GPIO;
+
+struct Sensor;
+/**
+ * @brief Указатель функции выделения памяти и подготовки экземпляра датчика
+ */
+//typedef void (*SensorAllocator)(Sensor* sensor, SensorType st);
+/**
+ * @brief Указатель функции инициализации датчика
+ */
+typedef bool(SensorInitializer)(void* sensor);
+/**
+ * @brief Указатель функции деинициализации датчика
+ */
+typedef bool(SensorDeinitializer)(void* sensor);
+/**
+ * @brief Указатель функции обновления значения датчика
+ */
+typedef UnitempStatus(SensorUpdater)(void* sensor);
+
+//Датчик
+typedef struct Sensor {
+    //Имя датчика
+    char* name;
+    //Температура
+    float temp;
+    //Относительная влажность
+    float hum;
+
+    //Тип датчика
+    SensorType type;
+    //Интерфейсы подключения
+    Interface interface;
+    //Статус последнего опроса датчика
+    UnitempStatus status;
+
+    //Экземпляр датчика
+    void* instance;
+    //SensorAllocator* allocator;
+    SensorInitializer* initializer;
+    SensorDeinitializer* deinitializer;
+    SensorUpdater* updater;
+
+} Sensor;
+
+/**
+ * @brief Получить имя типа датчика
+ * 
+ * @param st Тип датчика
+ * @return Указатель на строку с именем типа датчика
+ */
+const char* unitemp_getSensorTypeName(SensorType st);
+
+/**
+ * @brief Конвертация номера порта на корпусе FZ в GPIO 
+ * 
+ * @param name Номер порта на корпусе FZ
+ * @return Указатель на GPIO при успехе, NULL при ошибке
+ */
+const GPIO* unitemp_GPIO_getFromInt(uint8_t name);
+
+/**
+ * @brief Конвертация GPIO в номер на корпусе FZ
+ * 
+ * @param gpio Указатель на порт
+ * @return Номер порта на корпусе FZ
+ */
+uint8_t unitemp_GPIO_toInt(const GpioPin* gpio);
+
+/**
+ * @brief Выделение памяти под датчик
+ * 
+ * @param name Имя датчика
+ * @param st Тип датчика
+ * @return Указатель на датчик
+ */
+Sensor* unitemp_sensor_alloc(char* name, SensorType st);
+
+/**
+ * @brief Инициализация загруженных датчиков
+ * 
+ * @return Истина если всё прошло успешно
+ */
+bool unitemp_sensors_init(void);
+
+/**
+ * @brief Деинициализация загруженных датчиков
+ * 
+ * @return Истина если всё прошло успешно
+ */
+bool unitemp_sensors_deInit(void);
+
+/**
+ * @brief Получение данных указанного датчика
+ * 
+ * @param sensor Указатель на датчик
+ * @return Статус опроса датчика
+ */
+UnitempStatus unitemp_sensor_updateData(Sensor* sensor);
+
+/**
+ * @brief Функция загрузки датчиков с SD-карты
+ * 
+ * @return Истина если загрузка прошла успешно
+ */
+bool unitemp_sensors_load();
+
+/**
+ * @brief Сохранение настроек на SD-карту
+ * 
+ * @return Истина если сохранение прошло успешно
+ */
+bool unitemp_sensors_save(void);
+
+/**
+ * @brief Обновить данные со всех датчиков
+ */
+void unitemp_sensors_updateValues(void);
+
+#endif

+ 223 - 0
interfaces/OneWireSensor.c

@@ -0,0 +1,223 @@
+#include "OneWireSensor.h"
+#include "../Sensors.h"
+
+//Интервал опроса датчиков (мс)
+#define POLLING_INTERVAL 2000
+//Максимальное количество попугаев ожидания датчика
+#define POLLING_TIMEOUT_TICKS 10000
+
+void unitemp_oneWire_sensorAlloc(Sensor* sensor, SensorType st) {
+    OneWireSensor* instance = malloc(sizeof(OneWireSensor));
+    instance->interface = ONE_WIRE;
+    instance->lastPollingTime = 0xFFFFFFFF;
+
+    sensor->initializer = unitemp_oneWire_sensorInit;
+    sensor->deinitializer = unitemp_oneWire_sensorDeInit;
+    sensor->updater = unitemp_oneWire_updateData;
+
+    sensor->instance = instance;
+    sensor->type = st;
+}
+
+bool unitemp_oneWire_sensorInit(void* sensor) {
+    OneWireSensor* instance = ((Sensor*)sensor)->instance;
+    if(instance == NULL || instance->gpio == NULL) {
+        FURI_LOG_E(APP_NAME, "Sensor pointer is null!");
+        return false;
+    }
+    //Высокий уровень по умолчанию
+    furi_hal_gpio_write(instance->gpio->pin, true);
+    //Режим работы - OpenDrain, подтяжка включается на всякий случай
+    furi_hal_gpio_init(
+        instance->gpio->pin, //Порт FZ
+        GpioModeOutputOpenDrain, //Режим работы - открытый сток
+        GpioPullUp, //Принудительная подтяжка линии данных к питанию
+        GpioSpeedVeryHigh); //Скорость работы - максимальная
+    return true;
+}
+
+bool unitemp_oneWire_sensorDeInit(void* sensor) {
+    OneWireSensor* instance = ((Sensor*)sensor)->instance;
+    if(instance == NULL || instance->gpio == NULL) return false;
+    //Низкий уровень по умолчанию
+    furi_hal_gpio_write(instance->gpio->pin, false);
+    //Режим работы - аналог, подтяжка выключена
+    furi_hal_gpio_init(
+        instance->gpio->pin, //Порт FZ
+        GpioModeAnalog, //Режим работы - аналог
+        GpioPullNo, //Подтяжка выключена
+        GpioSpeedLow); //Скорость работы - минимальная
+    return true;
+}
+
+bool unitemp_oneWire_sensorSetGPIO(Sensor* sensor, const GPIO* gpio) {
+    if(sensor == NULL || gpio == NULL) return false;
+    OneWireSensor* instance = sensor->instance;
+    instance->gpio = gpio;
+    return true;
+}
+const GPIO* unitemp_oneWire_sensorGetGPIO(Sensor* sensor) {
+    if(sensor == NULL) return NULL;
+    OneWireSensor* instance = sensor->instance;
+    return instance->gpio;
+}
+
+UnitempStatus unitemp_oneWire_updateData(void* sensor) {
+    OneWireSensor* instance = ((Sensor*)sensor)->instance;
+    //Проверка на допустимость опроса датчика
+    if(furi_get_tick() - instance->lastPollingTime < POLLING_INTERVAL) {
+        //Возврат ошибки если последний опрос датчика был неудачным
+        if(instance->lastHum == -128.0f && instance->lastTemp == -128.0f) {
+            ((Sensor*)sensor)->hum = instance->lastHum;
+            ((Sensor*)sensor)->temp = instance->lastTemp;
+            return UT_TIMEOUT;
+        }
+
+        //Выход в случае раннего опроса
+        ((Sensor*)sensor)->hum = instance->lastHum;
+        ((Sensor*)sensor)->temp = instance->lastTemp;
+        return UT_EARLYPOOL;
+    }
+
+    //Массив для приёма данных
+    uint8_t data[5] = {0};
+
+    //Сохранение времени последнего опроса
+    instance->lastPollingTime = furi_get_tick();
+
+    /* Запрос */
+    //Опускание линии
+    furi_hal_gpio_write(instance->gpio->pin, false);
+    //Ожидание более 18 мс
+    furi_delay_ms(19);
+    //Выключение прерываний, чтобы ничто не мешало обработке данных
+    __disable_irq();
+    //Подъём линии
+    furi_hal_gpio_write(instance->gpio->pin, true);
+
+    /* Ответ датчика */
+    //Переменная-счётчик
+    uint16_t timeout = 0;
+
+    //Ожидание подъёма линии
+    while(!furi_hal_gpio_read(instance->gpio->pin)) {
+        timeout++;
+        if(timeout > POLLING_TIMEOUT_TICKS) {
+            //Включение прерываний
+            __enable_irq();
+            //Запись неправильных значений
+            instance->lastHum = -128.0f;
+            instance->lastTemp = -128.0f;
+            //Возврат признака отсутствующего датчика
+            return UT_TIMEOUT;
+        }
+    }
+    timeout = 0;
+
+    //Ожидание спада линии
+    while(furi_hal_gpio_read(instance->gpio->pin)) {
+        timeout++;
+        if(timeout > POLLING_TIMEOUT_TICKS) {
+            //Включение прерываний
+            __enable_irq();
+            //Запись неправильных значений
+            instance->lastHum = -128.0f;
+            instance->lastTemp = -128.0f;
+            //Возврат признака отсутствующего датчика
+            return UT_TIMEOUT;
+        }
+    }
+
+    //Ожидание подъёма линии
+    while(!furi_hal_gpio_read(instance->gpio->pin)) {
+        timeout++;
+        if(timeout > POLLING_TIMEOUT_TICKS) {
+            //Включение прерываний
+            __enable_irq();
+            //Запись неправильных значений
+            instance->lastHum = -128.0f;
+            instance->lastTemp = -128.0f;
+            //Возврат признака отсутствующего датчика
+            return UT_TIMEOUT;
+        }
+    }
+    timeout = 0;
+
+    //Ожидание спада линии
+    while(furi_hal_gpio_read(instance->gpio->pin)) {
+        timeout++;
+        if(timeout > POLLING_TIMEOUT_TICKS) {
+            //Включение прерываний
+            __enable_irq();
+            //Запись неправильных значений
+            instance->lastHum = -128.0f;
+            instance->lastTemp = -128.0f;
+            //Возврат признака отсутствующего датчика
+            return UT_TIMEOUT;
+        }
+    }
+
+    /* Чтение данных с датчика*/
+    //Приём 5 байт
+    for(uint8_t a = 0; a < 5; a++) {
+        for(uint8_t b = 7; b != 255; b--) {
+            uint16_t hT = 0, lT = 0;
+            //Пока линия в низком уровне, инкремент переменной lT
+            while(!furi_hal_gpio_read(instance->gpio->pin) && lT != 65535) lT++;
+            //Пока линия в высоком уровне, инкремент переменной hT
+            while(furi_hal_gpio_read(instance->gpio->pin) && hT != 65535) hT++;
+            //Если hT больше lT, то пришла единица
+            if(hT > lT) data[a] |= (1 << b);
+        }
+    }
+    //Включение прерываний
+    __enable_irq();
+
+    //Проверка контрольной суммы
+    if((uint8_t)(data[0] + data[1] + data[2] + data[3]) != data[4]) {
+        //Запись неправильных значений
+        instance->lastHum = -128.0f;
+        instance->lastTemp = -128.0f;
+        //Если контрольная сумма не совпала, возврат ошибки
+        return UT_BADCRC;
+    }
+
+    /* Преобразование данных в явный вид */
+    //DHT11 и DHT12
+    if(((Sensor*)sensor)->type == DHT11 || ((Sensor*)sensor)->type == DHT12_1W) {
+        instance->lastHum = (float)data[0];
+        instance->lastTemp = (float)data[2];
+
+        //Проверка на отрицательность температуры
+        if(data[3] != 0) {
+            //Проверка знака
+            if(!(data[3] & (1 << 7))) {
+                //Добавление положительной дробной части
+                instance->lastTemp += data[3] * 0.1f;
+            } else {
+                //А тут делаем отрицательное значение
+                data[3] &= ~(1 << 7);
+                instance->lastTemp += data[3] * 0.1f;
+                instance->lastTemp *= -1;
+            }
+        }
+    }
+
+    //DHT21, DHT22, AM2320
+    if(((Sensor*)sensor)->type == DHT21 || ((Sensor*)sensor)->type == DHT22 ||
+       ((Sensor*)sensor)->type == AM2320_1W) {
+        instance->lastHum = (float)(((uint16_t)data[0] << 8) | data[1]) / 10;
+        //Проверка на отрицательность температуры
+        if(!(data[2] & (1 << 7))) {
+            instance->lastTemp = (float)(((uint16_t)data[2] << 8) | data[3]) / 10;
+        } else {
+            data[2] &= ~(1 << 7);
+            instance->lastTemp = (float)(((uint16_t)data[2] << 8) | data[3]) / 10 * -1;
+        }
+    }
+
+    ((Sensor*)sensor)->hum = instance->lastHum;
+    ((Sensor*)sensor)->temp = instance->lastTemp;
+    //Возврат признака успешного опроса
+    return UT_OK;
+}

+ 68 - 0
interfaces/OneWireSensor.h

@@ -0,0 +1,68 @@
+#ifndef UNITEMP_ONE_WIRE
+#define UNITEMP_ONE_WIRE
+
+#include "../unitemp.h"
+
+//Интерфейс One Wire
+typedef struct {
+    //Тип интерфейса подключения датчика
+    Interface interface;
+    //Порт подключения датчика
+    const GPIO* gpio;
+    //Время последнего опроса
+    uint32_t lastPollingTime;
+    //Последнее успешное значение температуры
+    float lastTemp;
+    //Последнее успешное значение влажности
+    float lastHum;
+} OneWireSensor;
+
+/**
+ * @brief Инициализация датчика
+ * 
+ * @param sensor Указатель на инициализируемый датчик
+ * @return Истина если всё прошло успешно
+ */
+bool unitemp_oneWire_sensorInit(void* sensor);
+
+/**
+ * @brief Деинициализация датчика
+ * 
+ * @param sensor Указатель на инициализируемый датчик
+ * @return Истина если всё прошло успешно
+ */
+bool unitemp_oneWire_sensorDeInit(void* sensor);
+
+/**
+ * @brief Получение данных с датчика по однопроводному интерфейсу DHTxx и AM2xxx
+ * 
+ * @param sensor Указатель на датчик
+ * @return Статус опроса
+ */
+UnitempStatus unitemp_oneWire_updateData(void* sensor);
+
+/**
+ * @brief Установить порт датчика
+ * 
+ * @param sensor Указатель на датчик
+ * @param gpio Устанавливаемый порт
+ * @return Истина если всё ок
+ */
+bool unitemp_oneWire_sensorSetGPIO(Sensor* sensor, const GPIO* gpio);
+
+/**
+ * @brief Получить порт датчика
+ * 
+ * @param sensor Указатель на датчик
+ * @return Указатель на GPIO
+ */
+const GPIO* unitemp_oneWire_sensorGetGPIO(Sensor* sensor);
+
+/**
+ * @brief Выделение памяти под датчик на линии One Wire
+ * 
+ * @param sensor Указатель на датчик
+ * @param st Тип датчика
+ */
+void unitemp_oneWire_sensorAlloc(Sensor* sensor, SensorType st);
+#endif

+ 2 - 2
unitemp.c

@@ -1,6 +1,6 @@
 #include "unitemp.h"
-#include "interfaces/OneWire.h"
-#include "interfaces/Sensors.h"
+#include "interfaces/OneWireSensor.h"
+#include "Sensors.h"
 #include "scenes/Scenes.h"
 
 #include <furi_hal_power.h>

+ 1 - 1
unitemp.h

@@ -17,7 +17,7 @@
 
 /* Внутренние библиотеки */
 //Интерфейсы подключения датчиков
-#include "interfaces/Sensors.h"
+#include "Sensors.h"
 
 /* Объявление макроподстановок */
 //Имя приложения