Init
This commit is contained in:
commit
3e858fa48e
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
env.h
|
BIN
doc/1_LTR-390UV_Final_DS_V1_2.pdf
Normal file
BIN
doc/1_LTR-390UV_Final_DS_V1_2.pdf
Normal file
Binary file not shown.
BIN
doc/2.13inch_Touch_e-Paper_HAT.pdf
Normal file
BIN
doc/2.13inch_Touch_e-Paper_HAT.pdf
Normal file
Binary file not shown.
BIN
doc/2.13inch_e-Paper_Specification.pdf
Normal file
BIN
doc/2.13inch_e-Paper_Specification.pdf
Normal file
Binary file not shown.
BIN
doc/BME280_datasheet.pdf
Normal file
BIN
doc/BME280_datasheet.pdf
Normal file
Binary file not shown.
BIN
doc/ESP32_One_Sch.pdf
Normal file
BIN
doc/ESP32_One_Sch.pdf
Normal file
Binary file not shown.
BIN
doc/Environment_Sensor_HAT_SCH.pdf
Normal file
BIN
doc/Environment_Sensor_HAT_SCH.pdf
Normal file
Binary file not shown.
BIN
doc/GT911_Datasheet.pdf
Normal file
BIN
doc/GT911_Datasheet.pdf
Normal file
Binary file not shown.
BIN
doc/ICM-20948-v1.3.pdf
Normal file
BIN
doc/ICM-20948-v1.3.pdf
Normal file
Binary file not shown.
BIN
doc/PMSA003I_series.pdf
Normal file
BIN
doc/PMSA003I_series.pdf
Normal file
Binary file not shown.
BIN
doc/Sensirion_Gas-Sensors_SGP40_Datasheet.pdf
Normal file
BIN
doc/Sensirion_Gas-Sensors_SGP40_Datasheet.pdf
Normal file
Binary file not shown.
BIN
doc/TSL2591.pdf
Normal file
BIN
doc/TSL2591.pdf
Normal file
Binary file not shown.
BIN
doc/esp32_datasheet_en.pdf
Normal file
BIN
doc/esp32_datasheet_en.pdf
Normal file
Binary file not shown.
44129
doc/esp32_technical_reference_manual_en.pdf
Normal file
44129
doc/esp32_technical_reference_manual_en.pdf
Normal file
File diff suppressed because one or more lines are too long
335
metesp.ino
Normal file
335
metesp.ino
Normal file
@ -0,0 +1,335 @@
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "env.h"
|
||||
|
||||
#include "src/epd/epd_cfg.h"
|
||||
#include "src/epd/epd_driver.h"
|
||||
#include "src/epd/epd_paint.h"
|
||||
|
||||
#include "src/ntpt/ntp.h"
|
||||
#include "src/owm/owm.h"
|
||||
|
||||
#include "src/sensor/sensor.h"
|
||||
#include "src/touch/gt1151.h"
|
||||
|
||||
#include "src/influxdb/influx.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <stdlib.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiMulti.h>
|
||||
|
||||
#define PIN_SDA 18
|
||||
#define PIN_SCL 23
|
||||
|
||||
|
||||
/* Global Variables -----------------------------------------------------------*/
|
||||
|
||||
typedef enum {
|
||||
VIEW_MAIN = 0,
|
||||
VIEW_WEATHER, VIEW_WEATHER_ALT,
|
||||
VIEW_TEMP, VIEW_AIR,
|
||||
VIEW_CUSTOM,
|
||||
|
||||
VIEW_COUNT
|
||||
} views_t;
|
||||
|
||||
static const uint8_t view_count = 5;
|
||||
static uint8_t view_curr;
|
||||
static const views_t view_tab[view_count] = {
|
||||
VIEW_MAIN,
|
||||
VIEW_WEATHER,VIEW_WEATHER_ALT,
|
||||
VIEW_TEMP,VIEW_AIR
|
||||
};
|
||||
|
||||
static WiFiMulti wifiMulti;
|
||||
static TwoWire I2C = TwoWire(0);
|
||||
static strDateTime dateTime = {0};
|
||||
static Sensor* sensor = new Sensor(&I2C);
|
||||
static GT1151* touch = new GT1151(&I2C);
|
||||
static OWM* owm = new OWM(LOCATION, OPENWEATHER_API);
|
||||
static OWM* owm_alt = new OWM(LOCATION_ALT, OPENWEATHER_API);
|
||||
|
||||
static Influx* iflx = new Influx(NULL, owm, owm_alt);//add sensor
|
||||
|
||||
static NTPtime NTPch(NTP_URL);
|
||||
static bool time_update = false,
|
||||
ntp_update = true,
|
||||
weather_update = true,
|
||||
sensor_update = true,
|
||||
influx_w_update = true, influx_s_update = true,
|
||||
view_update = true, view_refresh = false;
|
||||
|
||||
static bool shutdownt = false;
|
||||
static int shutdownc = 0;
|
||||
|
||||
uint8_t *BlackImage;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* IRQ ------------------------------------------------------------------------*/
|
||||
hw_timer_t * timer = NULL;
|
||||
void IRAM_ATTR onSecondTimer() {
|
||||
dateTime.second += 1;
|
||||
if (dateTime.second == 60) {
|
||||
dateTime.minute += 1;
|
||||
dateTime.second = 0;
|
||||
if (dateTime.minute == 60) {
|
||||
dateTime.hour += 1;
|
||||
dateTime.minute = 0;
|
||||
if (dateTime.hour == 24) {
|
||||
dateTime.hour = 0;
|
||||
dateTime.minute = 0;
|
||||
dateTime.second = 0;
|
||||
}
|
||||
ntp_update = true;
|
||||
}
|
||||
if(dateTime.minute % 5) weather_update = true;
|
||||
if(dateTime.minute % 5) sensor_update = true;
|
||||
|
||||
if(dateTime.minute % 5) influx_w_update = true;
|
||||
if(dateTime.minute % 5) influx_s_update = true;
|
||||
view_update = true;
|
||||
time_update = true;
|
||||
|
||||
}
|
||||
if(touch->dev.holding) shutdownc++;
|
||||
else shutdownc = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void IRAM_ATTR onTouch(int8_t contacts, GTPoint *points) {
|
||||
if(touch->dev.holding) return;
|
||||
Serial.printf("Contacts: %d\n", contacts);
|
||||
for (uint8_t i = 0; i < contacts; i++) {
|
||||
Serial.printf("C%d: #%d %d,%d s:%d\n", i, points[i].id, points[i].x, points[i].y, points[i].a);
|
||||
yield();
|
||||
}
|
||||
if(points[0].x < 125) view_curr = (++view_curr % view_count);
|
||||
else view_curr = (--view_curr % view_count);
|
||||
view_update = true;
|
||||
}
|
||||
//x = 250 to 0
|
||||
//y = ????
|
||||
|
||||
/* Setup Functions -----------------------------------------------------------*/
|
||||
void setup_EPD(){
|
||||
//START EPD
|
||||
DEV_Module_Init();
|
||||
EPD_2IN13_V2_Init(EPD_2IN13_V2_FULL);
|
||||
EPD_2IN13_V2_Clear();
|
||||
delay(100);
|
||||
|
||||
//EPD STORAGE
|
||||
uint16_t Imagesize = ((EPD_2IN13_V2_WIDTH % 8 == 0) ? (EPD_2IN13_V2_WIDTH / 8 ) : (EPD_2IN13_V2_WIDTH / 8 + 1)) * EPD_2IN13_V2_HEIGHT;
|
||||
if ((BlackImage = (uint8_t *)malloc(Imagesize)) == NULL) exit(1);
|
||||
Paint_NewImage(BlackImage, EPD_2IN13_V2_WIDTH, EPD_2IN13_V2_HEIGHT, 270, WHITE);
|
||||
Paint_SelectImage(BlackImage);
|
||||
Paint_SetMirroring(MIRROR_HORIZONTAL);
|
||||
Paint_Clear(WHITE);
|
||||
|
||||
Paint_DrawIcon(89,54, ICON_LOGO, &FontIcon, BLACK, WHITE);
|
||||
Paint_DrawString_EN(29, 5, "Helcel", &Font45, WHITE, BLACK);
|
||||
Paint_SelectImage(BlackImage);
|
||||
EPD_2IN13_V2_Display(BlackImage);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
void setup_EPD_END(){
|
||||
Paint_Clear(WHITE);
|
||||
EPD_2IN13_V2_Init(EPD_2IN13_V2_FULL);
|
||||
EPD_2IN13_V2_DisplayPartBaseImage(BlackImage);
|
||||
EPD_2IN13_V2_Init(EPD_2IN13_V2_PART);
|
||||
Paint_SelectImage(BlackImage);
|
||||
}
|
||||
|
||||
void setup_TOUCH() {
|
||||
touch->setHandler(onTouch);
|
||||
touch->begin();
|
||||
}
|
||||
|
||||
void setup_WIFI(){
|
||||
uint8_t tries = 3;
|
||||
WIFI_REGISTER_AP(wifiMulti);
|
||||
while (wifiMulti.run() == WL_CONNECTED && tries-- >0) delay(500);
|
||||
}
|
||||
|
||||
void setup_TIMER(){
|
||||
timer = timerBegin(0, 80, true);
|
||||
timerAttachInterrupt(timer, &onSecondTimer, true);
|
||||
timerAlarmWrite(timer, 1000000, true);
|
||||
timerAlarmEnable(timer);
|
||||
}
|
||||
|
||||
|
||||
/* Setup Functions --------------------------------------------------------------*/
|
||||
void setup(){
|
||||
Serial.begin(115200);
|
||||
|
||||
I2C.begin(PIN_SDA, PIN_SCL, 100000);
|
||||
I2C.setPins(PIN_SDA,PIN_SCL);
|
||||
setup_EPD();
|
||||
setup_TOUCH();
|
||||
setup_WIFI();
|
||||
setup_TIMER();
|
||||
|
||||
iflx->check();
|
||||
|
||||
setup_EPD_END();
|
||||
}
|
||||
|
||||
|
||||
/* Update Functions-------------------------------------------------------------*/
|
||||
void updateNTP(){
|
||||
if (!ntp_update) return;
|
||||
if (wifiMulti.run() != WL_CONNECTED) return;
|
||||
strDateTime nDateTime = NTPch.getNTPtime(1.0, 1);
|
||||
if(nDateTime.valid){
|
||||
dateTime = nDateTime;
|
||||
time_update = true;
|
||||
ntp_update = false;
|
||||
}
|
||||
}
|
||||
|
||||
void updateWeather(){
|
||||
if (!weather_update) return;
|
||||
if (wifiMulti.run() != WL_CONNECTED) return;
|
||||
|
||||
if(owm!= NULL && !owm->update()) return;
|
||||
if(owm_alt!= NULL && !owm_alt->update()) return;
|
||||
weather_update = false;
|
||||
}
|
||||
|
||||
void updateTime(){
|
||||
if (!time_update) return;
|
||||
Paint_ClearWindows(170, EPD_2IN13_V2_WIDTH - Font24.Height, 170 + Font24.Width * 4.5, EPD_2IN13_V2_WIDTH, WHITE);
|
||||
if (!dateTime.valid) return;
|
||||
Paint_DrawTime(170, 98, &dateTime, &Font24, WHITE, BLACK);
|
||||
EPD_2IN13_V2_DisplayPart(BlackImage);
|
||||
time_update = false;
|
||||
}
|
||||
|
||||
void updateSensor(){
|
||||
if (!sensor_update) return;
|
||||
sensor->measure();
|
||||
sensor_update = false;
|
||||
}
|
||||
|
||||
ICON_tpe getWeatherIcon(int id){
|
||||
if(id>=200 && id<300){ //Thunder
|
||||
return ICON_CLOUD_THUNDER;
|
||||
}else if(id>=300 && id<400){//Drizzle
|
||||
return ICON_CLOUD_RAIN;
|
||||
}else if(id>=500 && id<600){//Rain
|
||||
return ICON_CLOUD_RAIN;
|
||||
}else if(id>=600 && id<700){//Snow
|
||||
return ICON_CLOUD_SNOW;
|
||||
}else if(id>=700 && id<800){//Warning
|
||||
return ICON_WARN;
|
||||
}else if(id>=800 && id<900){//Clear & Cloudy
|
||||
if(id==800) return ICON_SUN;
|
||||
else if(id==801) return ICON_CLOUD_SUN;
|
||||
else return ICON_CLOUD;
|
||||
}else{
|
||||
return ICON_WARN;
|
||||
}
|
||||
}
|
||||
|
||||
void refreshDisplay(){
|
||||
Paint_Clear(WHITE);
|
||||
EPD_2IN13_V2_Init(EPD_2IN13_V2_FULL);
|
||||
EPD_2IN13_V2_DisplayPartBaseImage(BlackImage);
|
||||
EPD_2IN13_V2_Init(EPD_2IN13_V2_PART);
|
||||
Paint_SelectImage(BlackImage);
|
||||
}
|
||||
|
||||
void updateDisplay(){
|
||||
// forceRefresh();
|
||||
if (!view_update) return;
|
||||
if (view_refresh) refreshDisplay();
|
||||
Paint_ClearWindows(0, 0, EPD_2IN13_V2_HEIGHT, EPD_2IN13_V2_WIDTH - Font24.Height, WHITE);
|
||||
Paint_ClearWindows(0, EPD_2IN13_V2_WIDTH - Font24.Height, 170, EPD_2IN13_V2_WIDTH, WHITE);
|
||||
switch(view_tab[view_curr]){
|
||||
case VIEW_MAIN:
|
||||
Paint_DrawIcon(0,0, ICON_LOGO,&FontIcon, BLACK, WHITE);
|
||||
Paint_DrawString_EN(60,0,"MAIN", &Font24, WHITE, BLACK);
|
||||
Paint_DrawIntUnit(0,30, 69,"", &Font24, BLACK, WHITE);
|
||||
break;
|
||||
case VIEW_WEATHER_ALT:
|
||||
case VIEW_WEATHER:
|
||||
{
|
||||
OWM* cowm = (view_tab[view_curr]==VIEW_WEATHER)?owm:owm_alt;
|
||||
if(!cowm->valid_weather) break;
|
||||
JsonObject weather_0 = cowm->weather["weather"][0];
|
||||
JsonObject weather_main = cowm->weather["main"];
|
||||
JsonObject weather_wind = cowm->weather["wind"];
|
||||
JsonObject weather_sys = cowm->weather["sys"];
|
||||
if(!weather_0 || !weather_main || !weather_sys || !weather_wind) break;
|
||||
Paint_DrawIcon(0,8, getWeatherIcon(weather_0["id"]), &FontIcon, BLACK, WHITE);
|
||||
Paint_DrawString_EN(2,EPD_2IN13_V2_WIDTH - 4 - Font16.Height,weather_0["description"], &Font16, WHITE, BLACK);
|
||||
Paint_DrawFltUnit(76,0,weather_main["temp"], "C", &Font24, BLACK, WHITE);
|
||||
Paint_DrawFltUnit(186,6,weather_main["feels_like"], "C", &Font12, BLACK, WHITE);
|
||||
Paint_DrawIntUnit(76,24,weather_main["pressure"], "hPa", &Font24, BLACK, WHITE);
|
||||
Paint_DrawIntUnit(76,48,weather_main["humidity"], "%", &Font24, BLACK, WHITE);
|
||||
Paint_DrawFltUnit(76,72,weather_wind["speed"], "m/s", &Font24, BLACK, WHITE);
|
||||
strDateTime sunrisedt = NTPtime::ConvertUnixTimestamp(NTPtime::adjustTimeZone(weather_sys["sunrise"], 1.0, 1));
|
||||
strDateTime sunsetdt = NTPtime::ConvertUnixTimestamp(NTPtime::adjustTimeZone(weather_sys["sunset"], 1.0, 1));
|
||||
Paint_DrawTime(20, 6, &sunrisedt, &Font12, WHITE, BLACK);
|
||||
Paint_DrawTime(20, 76, &sunsetdt, &Font12, WHITE, BLACK);
|
||||
}
|
||||
break;
|
||||
case VIEW_TEMP:
|
||||
Paint_DrawIcon(0,Font24.Height, ICON_TEMPERATURE,&FontIcon, BLACK, WHITE);
|
||||
Paint_DrawString_EN(2,0,"Temp", &Font24, WHITE, BLACK);
|
||||
Paint_DrawFltUnit(76,0,sensor->heatidx, "C", &Font24, BLACK, WHITE);
|
||||
Paint_DrawFltUnit(76,36,sensor->temp, "C", &Font24, BLACK, WHITE);
|
||||
Paint_DrawFltUnit(160,36,sensor->hum, "%", &Font24, BLACK, WHITE);
|
||||
Paint_DrawFltUnit(76,64,sensor->pres, "hPa", &Font24, BLACK, WHITE);
|
||||
break;
|
||||
case VIEW_AIR:
|
||||
Paint_DrawIcon(0,Font24.Height, ICON_POLUTION,&FontIcon, BLACK, WHITE);
|
||||
Paint_DrawString_EN(2,0,"Air", &Font24, WHITE, BLACK);
|
||||
Paint_DrawIntUnit(150,10, 69,"", &Font24, BLACK, WHITE);
|
||||
break;
|
||||
case VIEW_CUSTOM:
|
||||
Paint_DrawString_EN(60,0,"CUSTOM", &Font24, WHITE, BLACK);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
EPD_2IN13_V2_DisplayPart(BlackImage);
|
||||
view_update = false;
|
||||
}
|
||||
|
||||
void updateInflux(){
|
||||
if(wifiMulti.run() != WL_CONNECTED) return;
|
||||
iflx->record(influx_w_update, influx_s_update);
|
||||
influx_w_update = false;
|
||||
influx_s_update = false;
|
||||
}
|
||||
|
||||
|
||||
/* The main loop -------------------------------------------------------------*/
|
||||
void loop(){
|
||||
if(shutdownc >= 10){
|
||||
refreshDisplay();
|
||||
EPD_2IN13_V2_Sleep();
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
updateNTP();
|
||||
updateWeather();
|
||||
updateSensor();
|
||||
updateInflux();
|
||||
|
||||
touch->update();
|
||||
updateDisplay();
|
||||
updateTime();
|
||||
delay(50);
|
||||
if(!touch->dev.holding) shutdownc = 0;
|
||||
|
||||
|
||||
}
|
38
src/epd/convert.js
Normal file
38
src/epd/convert.js
Normal file
@ -0,0 +1,38 @@
|
||||
#!/bin/node
|
||||
|
||||
const fs = require('fs')
|
||||
|
||||
const fileContents = fs.readFileSync('./icon.h').toString()
|
||||
|
||||
let arr = fileContents.split('static unsigned char header_data[] = {');
|
||||
let imgcode = arr[1].replace('};','').replace('\n','').replace('\t','')
|
||||
let str = imgcode.split(',')
|
||||
|
||||
let charWidth = 32
|
||||
|
||||
let output = []
|
||||
let cur = 0;
|
||||
let idx = 0;
|
||||
let line = 0;
|
||||
for(let e of str){
|
||||
if(idx >=8){
|
||||
idx = 0;
|
||||
output.push('0x'+cur.toString(16)+',')
|
||||
++line;
|
||||
cur = 0;
|
||||
if(line >= 9){
|
||||
output.push('\n');
|
||||
line = 0;
|
||||
}
|
||||
}
|
||||
if(e == 0){
|
||||
cur |= (0x1 << (7-idx));
|
||||
}
|
||||
++idx;
|
||||
|
||||
}
|
||||
idx = 0;
|
||||
output.push('0x'+cur.toString(16)+',')
|
||||
|
||||
|
||||
console.log(output.join(''))
|
13
src/epd/debug.h
Normal file
13
src/epd/debug.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef __DEBUG_H
|
||||
#define __DEBUG_H
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
#define USE_DEBUG 0
|
||||
#if USE_DEBUG
|
||||
#define Debug(__info) Serial.print(__info)
|
||||
#else
|
||||
#define Debug(__info)
|
||||
#endif
|
||||
|
||||
#endif
|
46
src/epd/epd_cfg.cpp
Normal file
46
src/epd/epd_cfg.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include "epd_cfg.h"
|
||||
|
||||
void GPIO_Config(void){
|
||||
pinMode(EPD_BUSY_PIN, INPUT);
|
||||
pinMode(EPD_RST_PIN , OUTPUT);
|
||||
pinMode(EPD_DC_PIN , OUTPUT);
|
||||
|
||||
pinMode(EPD_SCK_PIN, OUTPUT);
|
||||
pinMode(EPD_MOSI_PIN, OUTPUT);
|
||||
pinMode(EPD_CS_PIN , OUTPUT);
|
||||
|
||||
digitalWrite(EPD_CS_PIN , HIGH);
|
||||
digitalWrite(EPD_SCK_PIN, LOW);
|
||||
}
|
||||
/******************************************************************************
|
||||
function: Module Initialize, the BCM2835 library and initialize the pins, SPI protocol
|
||||
parameter:
|
||||
Info:
|
||||
******************************************************************************/
|
||||
uint8_t DEV_Module_Init(void){
|
||||
GPIO_Config();
|
||||
|
||||
#ifdef USE_DEBUG
|
||||
Serial.begin(115200);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function:
|
||||
SPI read and write
|
||||
******************************************************************************/
|
||||
void DEV_SPI_WriteByte(uint8_t data){
|
||||
digitalWrite(EPD_CS_PIN, GPIO_PIN_RESET);
|
||||
|
||||
for (int i = 0; i < 8; i++){
|
||||
if ((data & 0x80) == 0) digitalWrite(EPD_MOSI_PIN, GPIO_PIN_RESET);
|
||||
else digitalWrite(EPD_MOSI_PIN, GPIO_PIN_SET);
|
||||
|
||||
data <<= 1;
|
||||
digitalWrite(EPD_SCK_PIN, GPIO_PIN_SET);
|
||||
digitalWrite(EPD_SCK_PIN, GPIO_PIN_RESET);
|
||||
}
|
||||
digitalWrite(EPD_CS_PIN, GPIO_PIN_SET);
|
||||
}
|
33
src/epd/epd_cfg.h
Normal file
33
src/epd/epd_cfg.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef _EPD_CONFIG_H_
|
||||
#define _DEV_CONFIG_H_
|
||||
#define _EPD_CONFIG_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* GPIO config
|
||||
**/
|
||||
#define EPD_SCK_PIN 14
|
||||
#define EPD_MOSI_PIN 13
|
||||
#define EPD_CS_PIN 5
|
||||
#define EPD_RST_PIN 19
|
||||
#define EPD_DC_PIN 0
|
||||
#define EPD_BUSY_PIN 4
|
||||
|
||||
#define GPIO_PIN_SET 1
|
||||
#define GPIO_PIN_RESET 0
|
||||
|
||||
/**
|
||||
* GPIO read and write
|
||||
**/
|
||||
#define DEV_Digital_Write(_pin, _value) digitalWrite(_pin, _value == 0? LOW:HIGH)
|
||||
#define DEV_Digital_Read(_pin) digitalRead(_pin)
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------*/
|
||||
uint8_t DEV_Module_Init(void);
|
||||
void DEV_SPI_WriteByte(uint8_t data);
|
||||
|
||||
#endif
|
352
src/epd/epd_driver.cpp
Normal file
352
src/epd/epd_driver.cpp
Normal file
@ -0,0 +1,352 @@
|
||||
/*****************************************************************************
|
||||
* | File : EPD_2in13_V2.c
|
||||
* | Author : Waveshare team
|
||||
* | Function : 2.13inch e-paper V2
|
||||
* | Info :
|
||||
*----------------
|
||||
* | This version: V3.0
|
||||
* | Date : 2019-06-13
|
||||
* | Info :
|
||||
* -----------------------------------------------------------------------------
|
||||
* V3.0(2019-06-13):
|
||||
* 1.Change name:
|
||||
* EPD_Reset() => EPD_2IN13_V2_Reset()
|
||||
* EPD_SendCommand() => EPD_2IN13_V2_SendCommand()
|
||||
* EPD_SendData() => EPD_2IN13_V2_SendData()
|
||||
* EPD_WaitUntilIdle() => EPD_2IN13_V2_ReadBusy()
|
||||
* EPD_Init() => EPD_2IN13_V2_Init()
|
||||
* EPD_Clear() => EPD_2IN13_V2_Clear()
|
||||
* EPD_Display() => EPD_2IN13_V2_Display()
|
||||
* EPD_Sleep() => EPD_2IN13_V2_Sleep()
|
||||
* 2.add:
|
||||
* EPD_2IN13_V2_DisplayPartBaseImage()
|
||||
* -----------------------------------------------------------------------------
|
||||
* V2.0(2018-11-14):
|
||||
* 1.Remove:ImageBuff[EPD_HEIGHT * EPD_WIDTH / 8]
|
||||
* 2.Change:EPD_2IN13_V2_Display(uint8_t *Image)
|
||||
* Need to pass parameters: pointer to cached data
|
||||
* 3.Change:
|
||||
* EPD_RST -> EPD_RST_PIN
|
||||
* EPD_DC -> EPD_DC_PIN
|
||||
* EPD_CS -> EPD_CS_PIN
|
||||
* EPD_BUSY -> EPD_BUSY_PIN
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documnetation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
******************************************************************************/
|
||||
#include "epd_driver.h"
|
||||
#include "debug.h"
|
||||
|
||||
const unsigned char EPD_2IN13_V2_lut_full_update[]= {
|
||||
0x80,0x60,0x40,0x00,0x00,0x00,0x00, //LUT0: BB: VS 0 ~7
|
||||
0x10,0x60,0x20,0x00,0x00,0x00,0x00, //LUT1: BW: VS 0 ~7
|
||||
0x80,0x60,0x40,0x00,0x00,0x00,0x00, //LUT2: WB: VS 0 ~7
|
||||
0x10,0x60,0x20,0x00,0x00,0x00,0x00, //LUT3: WW: VS 0 ~7
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00, //LUT4: VCOM: VS 0 ~7
|
||||
|
||||
0x03,0x03,0x00,0x00,0x02, // TP0 A~D RP0
|
||||
0x09,0x09,0x00,0x00,0x02, // TP1 A~D RP1
|
||||
0x03,0x03,0x00,0x00,0x02, // TP2 A~D RP2
|
||||
0x00,0x00,0x00,0x00,0x00, // TP3 A~D RP3
|
||||
0x00,0x00,0x00,0x00,0x00, // TP4 A~D RP4
|
||||
0x00,0x00,0x00,0x00,0x00, // TP5 A~D RP5
|
||||
0x00,0x00,0x00,0x00,0x00, // TP6 A~D RP6
|
||||
|
||||
0x15,0x41,0xA8,0x32,0x30,0x0A,
|
||||
};
|
||||
|
||||
const unsigned char EPD_2IN13_V2_lut_partial_update[]= { //20 bytes
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00, //LUT0: BB: VS 0 ~7
|
||||
0x80,0x00,0x00,0x00,0x00,0x00,0x00, //LUT1: BW: VS 0 ~7
|
||||
0x40,0x00,0x00,0x00,0x00,0x00,0x00, //LUT2: WB: VS 0 ~7
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00, //LUT3: WW: VS 0 ~7
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00, //LUT4: VCOM: VS 0 ~7
|
||||
|
||||
0x0A,0x00,0x00,0x00,0x00, // TP0 A~D RP0
|
||||
0x00,0x00,0x00,0x00,0x00, // TP1 A~D RP1
|
||||
0x00,0x00,0x00,0x00,0x00, // TP2 A~D RP2
|
||||
0x00,0x00,0x00,0x00,0x00, // TP3 A~D RP3
|
||||
0x00,0x00,0x00,0x00,0x00, // TP4 A~D RP4
|
||||
0x00,0x00,0x00,0x00,0x00, // TP5 A~D RP5
|
||||
0x00,0x00,0x00,0x00,0x00, // TP6 A~D RP6
|
||||
|
||||
0x15,0x41,0xA8,0x32,0x30,0x0A,
|
||||
};
|
||||
/******************************************************************************
|
||||
function : Software reset
|
||||
parameter:
|
||||
******************************************************************************/
|
||||
static void EPD_2IN13_V2_Reset(void){
|
||||
DEV_Digital_Write(EPD_RST_PIN, 1);
|
||||
delay(200);
|
||||
DEV_Digital_Write(EPD_RST_PIN, 0);
|
||||
delay(10);
|
||||
DEV_Digital_Write(EPD_RST_PIN, 1);
|
||||
delay(200);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : send command
|
||||
parameter:
|
||||
Reg : Command register
|
||||
******************************************************************************/
|
||||
static void EPD_2IN13_V2_SendCommand(uint8_t Reg){
|
||||
DEV_Digital_Write(EPD_DC_PIN, 0);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteByte(Reg);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : send data
|
||||
parameter:
|
||||
Data : Write data
|
||||
******************************************************************************/
|
||||
static void EPD_2IN13_V2_SendData(uint8_t Data){
|
||||
DEV_Digital_Write(EPD_DC_PIN, 1);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteByte(Data);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : Wait until the busy_pin goes LOW
|
||||
parameter:
|
||||
******************************************************************************/
|
||||
void EPD_2IN13_V2_ReadBusy(void){
|
||||
Debug("e-Paper busy\r\n");
|
||||
while(DEV_Digital_Read(EPD_BUSY_PIN) == 1) { //LOW: idle, HIGH: busy
|
||||
delay(100);
|
||||
}
|
||||
Debug("e-Paper busy release\r\n");
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : Turn On Display
|
||||
parameter:
|
||||
******************************************************************************/
|
||||
static void EPD_2IN13_V2_TurnOnDisplay(void){
|
||||
EPD_2IN13_V2_SendCommand(0x22);
|
||||
EPD_2IN13_V2_SendData(0xC7);
|
||||
EPD_2IN13_V2_SendCommand(0x20);
|
||||
EPD_2IN13_V2_ReadBusy();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : Turn On Display
|
||||
parameter:
|
||||
******************************************************************************/
|
||||
static void EPD_2IN13_V2_TurnOnDisplayPart(void){
|
||||
EPD_2IN13_V2_SendCommand(0x22);
|
||||
EPD_2IN13_V2_SendData(0x0C);
|
||||
EPD_2IN13_V2_SendCommand(0x20);
|
||||
EPD_2IN13_V2_ReadBusy();
|
||||
}
|
||||
/******************************************************************************
|
||||
function : Initialize the e-Paper register
|
||||
parameter:
|
||||
******************************************************************************/
|
||||
void EPD_2IN13_V2_Init(uint8_t Mode){
|
||||
uint8_t count;
|
||||
EPD_2IN13_V2_Reset();
|
||||
|
||||
if(Mode == EPD_2IN13_V2_FULL) {
|
||||
EPD_2IN13_V2_ReadBusy();
|
||||
EPD_2IN13_V2_SendCommand(0x12); // soft reset
|
||||
EPD_2IN13_V2_ReadBusy();
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x74); //set analog block control
|
||||
EPD_2IN13_V2_SendData(0x54);
|
||||
EPD_2IN13_V2_SendCommand(0x7E); //set digital block control
|
||||
EPD_2IN13_V2_SendData(0x3B);
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x01); //Driver output control
|
||||
EPD_2IN13_V2_SendData(0xF9);
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x11); //data entry mode
|
||||
EPD_2IN13_V2_SendData(0x01);
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x44); //set Ram-X address start/end position
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
EPD_2IN13_V2_SendData(0x0F); //0x0C-->(15+1)*8=128
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x45); //set Ram-Y address start/end position
|
||||
EPD_2IN13_V2_SendData(0xF9); //0xF9-->(249+1)=250
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x3C); //BorderWavefrom
|
||||
EPD_2IN13_V2_SendData(0x03);
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x2C); //VCOM Voltage
|
||||
EPD_2IN13_V2_SendData(0x55); //
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x03);
|
||||
EPD_2IN13_V2_SendData(EPD_2IN13_V2_lut_full_update[70]);
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x04); //
|
||||
EPD_2IN13_V2_SendData(EPD_2IN13_V2_lut_full_update[71]);
|
||||
EPD_2IN13_V2_SendData(EPD_2IN13_V2_lut_full_update[72]);
|
||||
EPD_2IN13_V2_SendData(EPD_2IN13_V2_lut_full_update[73]);
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x3A); //Dummy Line
|
||||
EPD_2IN13_V2_SendData(EPD_2IN13_V2_lut_full_update[74]);
|
||||
EPD_2IN13_V2_SendCommand(0x3B); //Gate time
|
||||
EPD_2IN13_V2_SendData(EPD_2IN13_V2_lut_full_update[75]);
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x32);
|
||||
for(count = 0; count < 70; count++) {
|
||||
EPD_2IN13_V2_SendData(EPD_2IN13_V2_lut_full_update[count]);
|
||||
}
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x4E); // set RAM x address count to 0;
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
EPD_2IN13_V2_SendCommand(0x4F); // set RAM y address count to 0X127;
|
||||
EPD_2IN13_V2_SendData(0xF9);
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
EPD_2IN13_V2_ReadBusy();
|
||||
} else if(Mode == EPD_2IN13_V2_PART) {
|
||||
EPD_2IN13_V2_SendCommand(0x2C); //VCOM Voltage
|
||||
EPD_2IN13_V2_SendData(0x26);
|
||||
|
||||
EPD_2IN13_V2_ReadBusy();
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x32);
|
||||
for(count = 0; count < 70; count++) {
|
||||
EPD_2IN13_V2_SendData(EPD_2IN13_V2_lut_partial_update[count]);
|
||||
}
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x37);
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
EPD_2IN13_V2_SendData(0x40);
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
EPD_2IN13_V2_SendData(0x00);
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x22);
|
||||
EPD_2IN13_V2_SendData(0xC0);
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x20);
|
||||
EPD_2IN13_V2_ReadBusy();
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x3C); //BorderWavefrom
|
||||
EPD_2IN13_V2_SendData(0x01);
|
||||
} else {
|
||||
Debug("error, the Mode is EPD_2IN13_FULL or EPD_2IN13_PART");
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : Clear screen
|
||||
parameter:
|
||||
******************************************************************************/
|
||||
void EPD_2IN13_V2_Clear(void){
|
||||
uint16_t Width, Height;
|
||||
Width = (EPD_2IN13_V2_WIDTH % 8 == 0)? (EPD_2IN13_V2_WIDTH / 8 ): (EPD_2IN13_V2_WIDTH / 8 + 1);
|
||||
Height = EPD_2IN13_V2_HEIGHT;
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x24);
|
||||
for (uint16_t j = 0; j < Height; j++) {
|
||||
for (uint16_t i = 0; i < Width; i++) {
|
||||
EPD_2IN13_V2_SendData(0XFF);
|
||||
}
|
||||
}
|
||||
|
||||
EPD_2IN13_V2_TurnOnDisplay();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : Sends the image buffer in RAM to e-Paper and displays
|
||||
parameter:
|
||||
******************************************************************************/
|
||||
void EPD_2IN13_V2_Display(uint8_t *Image){
|
||||
uint16_t Width, Height;
|
||||
Width = (EPD_2IN13_V2_WIDTH % 8 == 0)? (EPD_2IN13_V2_WIDTH / 8 ): (EPD_2IN13_V2_WIDTH / 8 + 1);
|
||||
Height = EPD_2IN13_V2_HEIGHT;
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x24);
|
||||
for (uint16_t j = 0; j < Height; j++) {
|
||||
for (uint16_t i = 0; i < Width; i++) {
|
||||
EPD_2IN13_V2_SendData(Image[i + j * Width]);
|
||||
}
|
||||
}
|
||||
EPD_2IN13_V2_TurnOnDisplay();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : The image of the previous frame must be uploaded, otherwise the
|
||||
first few seconds will display an exception.
|
||||
parameter:
|
||||
******************************************************************************/
|
||||
void EPD_2IN13_V2_DisplayPartBaseImage(uint8_t *Image){
|
||||
uint16_t Width, Height;
|
||||
Width = (EPD_2IN13_V2_WIDTH % 8 == 0)? (EPD_2IN13_V2_WIDTH / 8 ): (EPD_2IN13_V2_WIDTH / 8 + 1);
|
||||
Height = EPD_2IN13_V2_HEIGHT;
|
||||
|
||||
uint32_t Addr = 0;
|
||||
EPD_2IN13_V2_SendCommand(0x24);
|
||||
for (uint16_t j = 0; j < Height; j++) {
|
||||
for (uint16_t i = 0; i < Width; i++) {
|
||||
Addr = i + j * Width;
|
||||
EPD_2IN13_V2_SendData(Image[Addr]);
|
||||
}
|
||||
}
|
||||
EPD_2IN13_V2_SendCommand(0x26);
|
||||
for (uint16_t j = 0; j < Height; j++) {
|
||||
for (uint16_t i = 0; i < Width; i++) {
|
||||
Addr = i + j * Width;
|
||||
EPD_2IN13_V2_SendData(Image[Addr]);
|
||||
}
|
||||
}
|
||||
EPD_2IN13_V2_TurnOnDisplay();
|
||||
}
|
||||
|
||||
|
||||
void EPD_2IN13_V2_DisplayPart(uint8_t *Image){
|
||||
uint16_t Width, Height;
|
||||
Width = (EPD_2IN13_V2_WIDTH % 8 == 0)? (EPD_2IN13_V2_WIDTH / 8 ): (EPD_2IN13_V2_WIDTH / 8 + 1);
|
||||
Height = EPD_2IN13_V2_HEIGHT;
|
||||
EPD_2IN13_V2_SendCommand(0x24);
|
||||
for (uint16_t j = 0; j < Height; j++) {
|
||||
for (uint16_t i = 0; i < Width; i++) {
|
||||
EPD_2IN13_V2_SendData(Image[i + j * Width]);
|
||||
}
|
||||
}
|
||||
|
||||
EPD_2IN13_V2_TurnOnDisplayPart();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : Enter sleep mode
|
||||
parameter:
|
||||
******************************************************************************/
|
||||
void EPD_2IN13_V2_Sleep(void){
|
||||
EPD_2IN13_V2_SendCommand(0x22); //POWER OFF
|
||||
EPD_2IN13_V2_SendData(0xC3);
|
||||
EPD_2IN13_V2_SendCommand(0x20);
|
||||
|
||||
EPD_2IN13_V2_SendCommand(0x10); //enter deep sleep
|
||||
EPD_2IN13_V2_SendData(0x01);
|
||||
delay(100);
|
||||
}
|
72
src/epd/epd_driver.h
Normal file
72
src/epd/epd_driver.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*****************************************************************************
|
||||
* | File : EPD_2in13_V2.h
|
||||
* | Author : Waveshare team
|
||||
* | Function : 2.13inch e-paper V2
|
||||
* | Info :
|
||||
*----------------
|
||||
* | This version: V3.0
|
||||
* | Date : 2019-06-13
|
||||
* | Info :
|
||||
* -----------------------------------------------------------------------------
|
||||
* V3.0(2019-06-13):
|
||||
* 1.Change name:
|
||||
* EPD_Reset() => EPD_2IN13_V2_Reset()
|
||||
* EPD_SendCommand() => EPD_2IN13_V2_SendCommand()
|
||||
* EPD_SendData() => EPD_2IN13_V2_SendData()
|
||||
* EPD_WaitUntilIdle() => EPD_2IN13_V2_ReadBusy()
|
||||
* EPD_Init() => EPD_2IN13_V2_Init()
|
||||
* EPD_Clear() => EPD_2IN13_V2_Clear()
|
||||
* EPD_Display() => EPD_2IN13_V2_Display()
|
||||
* EPD_Sleep() => EPD_2IN13_V2_Sleep()
|
||||
* 2.add:
|
||||
* EPD_2IN13_V2_DisplayPartBaseImage()
|
||||
* -----------------------------------------------------------------------------
|
||||
* V2.0(2018-11-14):
|
||||
* 1.Remove:ImageBuff[EPD_HEIGHT * EPD_WIDTH / 8]
|
||||
* 2.Change:EPD_2IN13_V2_Display(uint8_t *Image)
|
||||
* Need to pass parameters: pointer to cached data
|
||||
* 3.Change:
|
||||
* EPD_RST -> EPD_RST_PIN
|
||||
* EPD_DC -> EPD_DC_PIN
|
||||
* EPD_CS -> EPD_CS_PIN
|
||||
* EPD_BUSY -> EPD_BUSY_PIN
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documnetation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
******************************************************************************/
|
||||
#ifndef _EPD_2IN13_V2_H_
|
||||
#define _EPD_2IN13_V2_H_
|
||||
|
||||
#include "epd_cfg.h"
|
||||
|
||||
// Display resolution
|
||||
#define EPD_2IN13_V2_WIDTH 122
|
||||
#define EPD_2IN13_V2_HEIGHT 250
|
||||
|
||||
#define EPD_2IN13_V2_FULL 0
|
||||
#define EPD_2IN13_V2_PART 1
|
||||
|
||||
void EPD_2IN13_V2_Init(uint8_t Mode);
|
||||
void EPD_2IN13_V2_Clear(void);
|
||||
void EPD_2IN13_V2_Display(uint8_t *Image);
|
||||
void EPD_2IN13_V2_DisplayPart(uint8_t *Image);
|
||||
void EPD_2IN13_V2_DisplayPartBaseImage(uint8_t *Image);
|
||||
void EPD_2IN13_V2_Sleep(void);
|
||||
|
||||
#endif
|
730
src/epd/epd_paint.cpp
Normal file
730
src/epd/epd_paint.cpp
Normal file
@ -0,0 +1,730 @@
|
||||
/******************************************************************************
|
||||
* | File : GUI_Paint.c
|
||||
* | Author : Waveshare electronics
|
||||
* | Function : Achieve drawing: draw points, lines, boxes, circles and
|
||||
* their size, solid dotted line, solid rectangle hollow
|
||||
* rectangle, solid circle hollow circle.
|
||||
* | Info :
|
||||
* Achieve display characters: Display a single character, string, number
|
||||
* Achieve time display: adaptive size display time minutes and seconds
|
||||
*----------------
|
||||
* | This version: V3.2
|
||||
* | Date : 2020-07-23
|
||||
* | Info :
|
||||
* -----------------------------------------------------------------------------
|
||||
* V3.2(2020-07-23):
|
||||
* 1. Change: Paint_SetScale(uint8_t scale)
|
||||
* Add scale 7 for 5.65f e-Parper
|
||||
* 2. Change: Paint_SetPixel(uint16_t Xpoint, uint16_t Ypoint, uint16_t Color)
|
||||
* Add the branch for scale 7
|
||||
* 3. Change: Paint_Clear(uint16_t Color)
|
||||
* Add the branch for scale 7
|
||||
*
|
||||
* V3.1(2019-10-10):
|
||||
* 1. Add gray level
|
||||
* PAINT Add Scale
|
||||
* 2. Add void Paint_SetScale(uint8_t scale);
|
||||
*
|
||||
* V3.0(2019-04-18):
|
||||
* 1.Change:
|
||||
* Paint_DrawPoint(..., DOT_STYLE DOT_STYLE)
|
||||
* => Paint_DrawPoint(..., DOT_STYLE Dot_Style)
|
||||
* Paint_DrawLine(..., LINE_STYLE Line_Style, DOT_PIXEL Dot_Pixel)
|
||||
* => Paint_DrawLine(..., DOT_PIXEL Line_width, LINE_STYLE Line_Style)
|
||||
* Paint_DrawRectangle(..., DRAW_FILL Filled, DOT_PIXEL Dot_Pixel)
|
||||
* => Paint_DrawRectangle(..., DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
|
||||
* Paint_DrawCircle(..., DRAW_FILL Draw_Fill, DOT_PIXEL Dot_Pixel)
|
||||
* => Paint_DrawCircle(..., DOT_PIXEL Line_width, DRAW_FILL Draw_Filll)
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* V2.0(2018-11-15):
|
||||
* 1.add: Paint_NewImage()
|
||||
* Create an image's properties
|
||||
* 2.add: Paint_SelectImage()
|
||||
* Select the picture to be drawn
|
||||
* 3.add: Paint_SetRotate()
|
||||
* Set the direction of the cache
|
||||
* 4.add: Paint_RotateImage()
|
||||
* Can flip the picture, Support 0-360 degrees,
|
||||
* but only 90.180.270 rotation is better
|
||||
* 4.add: Paint_SetMirroring()
|
||||
* Can Mirroring the picture, horizontal, vertical, origin
|
||||
* 5.add: Paint_DrawString_CN()
|
||||
* Can display Chinese(GB1312)
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* V1.0(2018-07-17):
|
||||
* Create library
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documnetation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
******************************************************************************/
|
||||
#include "epd_paint.h"
|
||||
#include "epd_cfg.h"
|
||||
#include "debug.h"
|
||||
#include <Arduino.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h> //memset()
|
||||
#include <math.h>
|
||||
|
||||
PAINT Paint;
|
||||
|
||||
/******************************************************************************
|
||||
function: Create Image
|
||||
parameter:
|
||||
image : Pointer to the image cache
|
||||
width : The width of the picture
|
||||
Height : The height of the picture
|
||||
Color : Whether the picture is inverted
|
||||
******************************************************************************/
|
||||
void Paint_NewImage(uint8_t *image, uint16_t Width, uint16_t Height, uint16_t Rotate, uint16_t Color){
|
||||
Paint.Image = NULL;
|
||||
Paint.Image = image;
|
||||
|
||||
Paint.WidthMemory = Width;
|
||||
Paint.HeightMemory = Height;
|
||||
Paint.Color = Color;
|
||||
Paint.Scale = 2;
|
||||
Paint.WidthByte = (Width % 8 == 0)? (Width / 8 ): (Width / 8 + 1);
|
||||
Paint.HeightByte = Height;
|
||||
|
||||
Paint.Rotate = Rotate;
|
||||
Paint.Mirror = MIRROR_NONE;
|
||||
|
||||
if(Rotate == ROTATE_0 || Rotate == ROTATE_180) {
|
||||
Paint.Width = Width;
|
||||
Paint.Height = Height;
|
||||
} else {
|
||||
Paint.Width = Height;
|
||||
Paint.Height = Width;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function: Select Image
|
||||
parameter:
|
||||
image : Pointer to the image cache
|
||||
******************************************************************************/
|
||||
void Paint_SelectImage(uint8_t *image){
|
||||
Paint.Image = image;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function: Select Image Rotate
|
||||
parameter:
|
||||
Rotate : 0,90,180,270
|
||||
******************************************************************************/
|
||||
void Paint_SetRotate(uint16_t Rotate){
|
||||
if(Rotate == ROTATE_0 || Rotate == ROTATE_90 || Rotate == ROTATE_180 || Rotate == ROTATE_270) {
|
||||
// Debug("Set image Rotate %d\r\n", Rotate);
|
||||
Paint.Rotate = Rotate;
|
||||
} else {
|
||||
Debug("rotate = 0, 90, 180, 270\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function: Select Image mirror
|
||||
parameter:
|
||||
mirror :Not mirror,Horizontal mirror,Vertical mirror,Origin mirror
|
||||
******************************************************************************/
|
||||
void Paint_SetMirroring(uint8_t mirror){
|
||||
if(mirror == MIRROR_NONE || mirror == MIRROR_HORIZONTAL ||
|
||||
mirror == MIRROR_VERTICAL || mirror == MIRROR_ORIGIN) {
|
||||
Paint.Mirror = mirror;
|
||||
} else {
|
||||
Debug("mirror should be MIRROR_NONE, MIRROR_HORIZONTAL, \
|
||||
MIRROR_VERTICAL or MIRROR_ORIGIN\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Paint_SetScale(uint8_t scale){
|
||||
if(scale == 2){
|
||||
Paint.Scale = scale;
|
||||
Paint.WidthByte = (Paint.WidthMemory % 8 == 0)? (Paint.WidthMemory / 8 ): (Paint.WidthMemory / 8 + 1);
|
||||
}else if(scale == 4) {
|
||||
Paint.Scale = scale;
|
||||
Paint.WidthByte = (Paint.WidthMemory % 4 == 0)? (Paint.WidthMemory / 4 ): (Paint.WidthMemory / 4 + 1);
|
||||
}else if(scale == 7) {
|
||||
Paint.Scale = 7;
|
||||
Paint.WidthByte = (Paint.WidthMemory % 2 == 0)? (Paint.WidthMemory / 2 ): (Paint.WidthMemory / 2 + 1);
|
||||
}else {
|
||||
Debug("Set Scale Input parameter error\r\n");
|
||||
Debug("Scale Only support: 2 4 7\r\n");
|
||||
}
|
||||
}
|
||||
/******************************************************************************
|
||||
function: Draw Pixels
|
||||
parameter:
|
||||
Xpoint : At point X
|
||||
Ypoint : At point Y
|
||||
Color : Painted colors
|
||||
******************************************************************************/
|
||||
void Paint_SetPixel(uint16_t Xpoint, uint16_t Ypoint, uint16_t Color){
|
||||
if(Xpoint > Paint.Width || Ypoint > Paint.Height){
|
||||
Debug("Exceeding display boundaries\r\n");
|
||||
return;
|
||||
}
|
||||
uint16_t X, Y;
|
||||
switch(Paint.Rotate) {
|
||||
case 0:
|
||||
X = Xpoint;
|
||||
Y = Ypoint;
|
||||
break;
|
||||
case 90:
|
||||
X = Paint.WidthMemory - Ypoint - 1;
|
||||
Y = Xpoint;
|
||||
break;
|
||||
case 180:
|
||||
X = Paint.WidthMemory - Xpoint - 1;
|
||||
Y = Paint.HeightMemory - Ypoint - 1;
|
||||
break;
|
||||
case 270:
|
||||
X = Ypoint;
|
||||
Y = Paint.HeightMemory - Xpoint - 1;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
switch(Paint.Mirror) {
|
||||
case MIRROR_NONE:
|
||||
break;
|
||||
case MIRROR_HORIZONTAL:
|
||||
X = Paint.WidthMemory - X - 1;
|
||||
break;
|
||||
case MIRROR_VERTICAL:
|
||||
Y = Paint.HeightMemory - Y - 1;
|
||||
break;
|
||||
case MIRROR_ORIGIN:
|
||||
X = Paint.WidthMemory - X - 1;
|
||||
Y = Paint.HeightMemory - Y - 1;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if(X > Paint.WidthMemory || Y > Paint.HeightMemory){
|
||||
Debug("Exceeding display boundaries\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(Paint.Scale == 2){
|
||||
uint32_t Addr = X / 8 + Y * Paint.WidthByte;
|
||||
uint8_t Rdata = Paint.Image[Addr];
|
||||
if(Color == BLACK)
|
||||
Paint.Image[Addr] = Rdata & ~(0x80 >> (X % 8));
|
||||
else
|
||||
Paint.Image[Addr] = Rdata | (0x80 >> (X % 8));
|
||||
}else if(Paint.Scale == 4){
|
||||
uint32_t Addr = X / 4 + Y * Paint.WidthByte;
|
||||
Color = Color % 4;//Guaranteed color scale is 4 --- 0~3
|
||||
uint8_t Rdata = Paint.Image[Addr];
|
||||
|
||||
Rdata = Rdata & (~(0xC0 >> ((X % 4)*2)));
|
||||
Paint.Image[Addr] = Rdata | ((Color << 6) >> ((X % 4)*2));
|
||||
}else if(Paint.Scale == 7){
|
||||
uint16_t Width = Paint.WidthMemory*3%8 == 0 ? Paint.WidthMemory*3/8 : Paint.WidthMemory*3/8+1;
|
||||
uint32_t Addr = (Xpoint * 3) / 8 + Ypoint * Width;
|
||||
uint8_t shift, Rdata, Rdata2;
|
||||
shift = (Xpoint+Ypoint*Paint.HeightMemory) % 8;
|
||||
|
||||
switch(shift) {
|
||||
case 0 :
|
||||
Rdata = Paint.Image[Addr] & 0x1f;
|
||||
Rdata = Rdata | ((Color << 5) & 0xe0);
|
||||
Paint.Image[Addr] = Rdata;
|
||||
break;
|
||||
case 1 :
|
||||
Rdata = Paint.Image[Addr] & 0xe3;
|
||||
Rdata = Rdata | ((Color << 2) & 0x1c);
|
||||
Paint.Image[Addr] = Rdata;
|
||||
break;
|
||||
case 2 :
|
||||
Rdata = Paint.Image[Addr] & 0xfc;
|
||||
Rdata2 = Paint.Image[Addr + 1] & 0x7f;
|
||||
Rdata = Rdata | ((Color >> 1) & 0x03);
|
||||
Rdata2 = Rdata2 | ((Color << 7) & 0x80);
|
||||
Paint.Image[Addr] = Rdata;
|
||||
Paint.Image[Addr + 1] = Rdata2;
|
||||
break;
|
||||
case 3 :
|
||||
Rdata = Paint.Image[Addr] & 0x8f;
|
||||
Rdata = Rdata | ((Color << 4) & 0x70);
|
||||
Paint.Image[Addr] = Rdata;
|
||||
break;
|
||||
case 4 :
|
||||
Rdata = Paint.Image[Addr] & 0xf1;
|
||||
Rdata = Rdata | ((Color << 1) & 0x0e);
|
||||
Paint.Image[Addr] = Rdata;
|
||||
break;
|
||||
case 5 :
|
||||
Rdata = Paint.Image[Addr] & 0xfe;
|
||||
Rdata2 = Paint.Image[Addr + 1] & 0x3f;
|
||||
Rdata = Rdata | ((Color >> 2) & 0x01);
|
||||
Rdata2 = Rdata2 | ((Color << 6) & 0xc0);
|
||||
Paint.Image[Addr] = Rdata;
|
||||
Paint.Image[Addr + 1] = Rdata2;
|
||||
break;
|
||||
case 6 :
|
||||
Rdata = Paint.Image[Addr] & 0xc7;
|
||||
Rdata = Rdata | ((Color << 3) & 0x38);
|
||||
Paint.Image[Addr] = Rdata;
|
||||
break;
|
||||
case 7 :
|
||||
Rdata = Paint.Image[Addr] & 0xf8;
|
||||
Rdata = Rdata | (Color & 0x07);
|
||||
Paint.Image[Addr] = Rdata;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function: Clear the color of the picture
|
||||
parameter:
|
||||
Color : Painted colors
|
||||
******************************************************************************/
|
||||
void Paint_Clear(uint16_t Color){
|
||||
if(Paint.Scale == 2 || Paint.Scale == 4) {
|
||||
for (uint16_t Y = 0; Y < Paint.HeightByte; Y++) {
|
||||
for (uint16_t X = 0; X < Paint.WidthByte; X++ ) {//8 pixel = 1 byte
|
||||
uint32_t Addr = X + Y*Paint.WidthByte;
|
||||
Paint.Image[Addr] = Color;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(Paint.Scale == 7) {
|
||||
Color = (uint8_t)Color;
|
||||
uint16_t Width = (Paint.WidthMemory * 3 % 8 == 0)? (Paint.WidthMemory * 3 / 8 ): (Paint.WidthMemory * 3 / 8 + 1);
|
||||
for (uint16_t Y = 0; Y < Paint.HeightByte; Y++) {
|
||||
for (uint16_t X = 0; X < Width; X++ ) {
|
||||
uint32_t Addr = X + Y * Width;
|
||||
if((X + Y * Width)%3 == 0)
|
||||
Paint.Image[Addr] = ((Color<<5) | (Color<<2) | (Color>>1));
|
||||
else if((X + Y * Width)%3 == 1)
|
||||
Paint.Image[Addr] = ((Color<<7) | (Color<<4) | (Color<<1) | (Color>>2));
|
||||
else if((X + Y * Width)%3 == 2)
|
||||
Paint.Image[Addr] = ((Color<<6) | (Color<<3) | Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function: Clear the color of a window
|
||||
parameter:
|
||||
Xstart : x starting point
|
||||
Ystart : Y starting point
|
||||
Xend : x end point
|
||||
Yend : y end point
|
||||
Color : Painted colors
|
||||
******************************************************************************/
|
||||
void Paint_ClearWindows(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint16_t Color){
|
||||
uint16_t X, Y;
|
||||
for (Y = Ystart; Y < Yend; Y++) {
|
||||
for (X = Xstart; X < Xend; X++) {//8 pixel = 1 byte
|
||||
Paint_SetPixel(X, Y, Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function: Draw Point(Xpoint, Ypoint) Fill the color
|
||||
parameter:
|
||||
Xpoint : The Xpoint coordinate of the point
|
||||
Ypoint : The Ypoint coordinate of the point
|
||||
Color : Painted color
|
||||
Dot_Pixel : point size
|
||||
Dot_Style : point Style
|
||||
******************************************************************************/
|
||||
void Paint_DrawPoint(uint16_t Xpoint, uint16_t Ypoint, uint16_t Color,
|
||||
DOT_PIXEL Dot_Pixel, DOT_STYLE Dot_Style){
|
||||
if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
|
||||
Debug("Paint_DrawPoint Input exceeds the normal display range\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t XDir_Num , YDir_Num;
|
||||
if (Dot_Style == DOT_FILL_AROUND) {
|
||||
for (XDir_Num = 0; XDir_Num < 2 * Dot_Pixel - 1; XDir_Num++) {
|
||||
for (YDir_Num = 0; YDir_Num < 2 * Dot_Pixel - 1; YDir_Num++) {
|
||||
if(Xpoint + XDir_Num - Dot_Pixel < 0 || Ypoint + YDir_Num - Dot_Pixel < 0)
|
||||
break;
|
||||
Paint_SetPixel(Xpoint + XDir_Num - Dot_Pixel, Ypoint + YDir_Num - Dot_Pixel, Color);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (XDir_Num = 0; XDir_Num < Dot_Pixel; XDir_Num++) {
|
||||
for (YDir_Num = 0; YDir_Num < Dot_Pixel; YDir_Num++) {
|
||||
Paint_SetPixel(Xpoint + XDir_Num - 1, Ypoint + YDir_Num - 1, Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function: Draw a line of arbitrary slope
|
||||
parameter:
|
||||
Xstart :Starting Xpoint point coordinates
|
||||
Ystart :Starting Xpoint point coordinates
|
||||
Xend :End point Xpoint coordinate
|
||||
Yend :End point Ypoint coordinate
|
||||
Color :The color of the line segment
|
||||
Line_width : Line width
|
||||
Line_Style: Solid and dotted lines
|
||||
******************************************************************************/
|
||||
void Paint_DrawLine(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend,
|
||||
uint16_t Color, DOT_PIXEL Line_width, LINE_STYLE Line_Style)
|
||||
{
|
||||
if (Xstart > Paint.Width || Ystart > Paint.Height ||
|
||||
Xend > Paint.Width || Yend > Paint.Height) {
|
||||
Debug("Paint_DrawLine Input exceeds the normal display range\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t Xpoint = Xstart;
|
||||
uint16_t Ypoint = Ystart;
|
||||
int dx = (int)Xend - (int)Xstart >= 0 ? Xend - Xstart : Xstart - Xend;
|
||||
int dy = (int)Yend - (int)Ystart <= 0 ? Yend - Ystart : Ystart - Yend;
|
||||
|
||||
int XAddway = Xstart < Xend ? 1 : -1;
|
||||
int YAddway = Ystart < Yend ? 1 : -1;
|
||||
|
||||
int Esp = dx + dy;
|
||||
char Dotted_Len = 0;
|
||||
|
||||
for (;;) {
|
||||
Dotted_Len++;
|
||||
if (Line_Style == LINE_STYLE_DOTTED && Dotted_Len % 3 == 0) {
|
||||
Paint_DrawPoint(Xpoint, Ypoint, IMAGE_BACKGROUND, Line_width, DOT_STYLE_DFT);
|
||||
Dotted_Len = 0;
|
||||
} else {
|
||||
Paint_DrawPoint(Xpoint, Ypoint, Color, Line_width, DOT_STYLE_DFT);
|
||||
}
|
||||
if (2 * Esp >= dy) {
|
||||
if (Xpoint == Xend)
|
||||
break;
|
||||
Esp += dy;
|
||||
Xpoint += XAddway;
|
||||
}
|
||||
if (2 * Esp <= dx) {
|
||||
if (Ypoint == Yend)
|
||||
break;
|
||||
Esp += dx;
|
||||
Ypoint += YAddway;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function: Draw a rectangle
|
||||
parameter:
|
||||
Xstart :Rectangular Starting Xpoint point coordinates
|
||||
Ystart :Rectangular Starting Xpoint point coordinates
|
||||
Xend :Rectangular End point Xpoint coordinate
|
||||
Yend :Rectangular End point Ypoint coordinate
|
||||
Color :The color of the Rectangular segment
|
||||
Line_width: Line width
|
||||
Draw_Fill : Whether to fill the inside of the rectangle
|
||||
******************************************************************************/
|
||||
void Paint_DrawRectangle(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend,
|
||||
uint16_t Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill){
|
||||
if (Xstart > Paint.Width || Ystart > Paint.Height ||
|
||||
Xend > Paint.Width || Yend > Paint.Height) {
|
||||
Debug("Input exceeds the normal display range\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Draw_Fill) {
|
||||
uint16_t Ypoint;
|
||||
for(Ypoint = Ystart; Ypoint < Yend; Ypoint++) {
|
||||
Paint_DrawLine(Xstart, Ypoint, Xend, Ypoint, Color , Line_width, LINE_STYLE_SOLID);
|
||||
}
|
||||
} else {
|
||||
Paint_DrawLine(Xstart, Ystart, Xend, Ystart, Color, Line_width, LINE_STYLE_SOLID);
|
||||
Paint_DrawLine(Xstart, Ystart, Xstart, Yend, Color, Line_width, LINE_STYLE_SOLID);
|
||||
Paint_DrawLine(Xend, Yend, Xend, Ystart, Color, Line_width, LINE_STYLE_SOLID);
|
||||
Paint_DrawLine(Xend, Yend, Xstart, Yend, Color, Line_width, LINE_STYLE_SOLID);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function: Use the 8-point method to draw a circle of the
|
||||
specified size at the specified position->
|
||||
parameter:
|
||||
X_Center :Center X coordinate
|
||||
Y_Center :Center Y coordinate
|
||||
Radius :circle Radius
|
||||
Color :The color of the :circle segment
|
||||
Line_width: Line width
|
||||
Draw_Fill : Whether to fill the inside of the Circle
|
||||
******************************************************************************/
|
||||
void Paint_DrawCircle(uint16_t X_Center, uint16_t Y_Center, uint16_t Radius,
|
||||
uint16_t Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill){
|
||||
if (X_Center > Paint.Width || Y_Center >= Paint.Height) {
|
||||
Debug("Paint_DrawCircle Input exceeds the normal display range\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t XCurrent, YCurrent;
|
||||
XCurrent = 0;
|
||||
YCurrent = Radius;
|
||||
|
||||
int16_t Esp = 3 - (Radius << 1 );
|
||||
|
||||
int16_t sCountY;
|
||||
|
||||
if (Draw_Fill == DRAW_FILL_FULL) {
|
||||
while (XCurrent <= YCurrent ) {
|
||||
for (sCountY = XCurrent; sCountY <= YCurrent; sCountY ++ ) {
|
||||
Paint_DrawPoint(X_Center + XCurrent, Y_Center + sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//1
|
||||
Paint_DrawPoint(X_Center - XCurrent, Y_Center + sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//2
|
||||
Paint_DrawPoint(X_Center - sCountY, Y_Center + XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//3
|
||||
Paint_DrawPoint(X_Center - sCountY, Y_Center - XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//4
|
||||
Paint_DrawPoint(X_Center - XCurrent, Y_Center - sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//5
|
||||
Paint_DrawPoint(X_Center + XCurrent, Y_Center - sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//6
|
||||
Paint_DrawPoint(X_Center + sCountY, Y_Center - XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//7
|
||||
Paint_DrawPoint(X_Center + sCountY, Y_Center + XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);
|
||||
}
|
||||
if (Esp < 0 )
|
||||
Esp += 4 * XCurrent + 6;
|
||||
else {
|
||||
Esp += 10 + 4 * (XCurrent - YCurrent );
|
||||
YCurrent --;
|
||||
}
|
||||
XCurrent ++;
|
||||
}
|
||||
} else {
|
||||
while (XCurrent <= YCurrent ) {
|
||||
Paint_DrawPoint(X_Center + XCurrent, Y_Center + YCurrent, Color, Line_width, DOT_STYLE_DFT);//1
|
||||
Paint_DrawPoint(X_Center - XCurrent, Y_Center + YCurrent, Color, Line_width, DOT_STYLE_DFT);//2
|
||||
Paint_DrawPoint(X_Center - YCurrent, Y_Center + XCurrent, Color, Line_width, DOT_STYLE_DFT);//3
|
||||
Paint_DrawPoint(X_Center - YCurrent, Y_Center - XCurrent, Color, Line_width, DOT_STYLE_DFT);//4
|
||||
Paint_DrawPoint(X_Center - XCurrent, Y_Center - YCurrent, Color, Line_width, DOT_STYLE_DFT);//5
|
||||
Paint_DrawPoint(X_Center + XCurrent, Y_Center - YCurrent, Color, Line_width, DOT_STYLE_DFT);//6
|
||||
Paint_DrawPoint(X_Center + YCurrent, Y_Center - XCurrent, Color, Line_width, DOT_STYLE_DFT);//7
|
||||
Paint_DrawPoint(X_Center + YCurrent, Y_Center + XCurrent, Color, Line_width, DOT_STYLE_DFT);//0
|
||||
|
||||
if (Esp < 0 )
|
||||
Esp += 4 * XCurrent + 6;
|
||||
else {
|
||||
Esp += 10 + 4 * (XCurrent - YCurrent );
|
||||
YCurrent --;
|
||||
}
|
||||
XCurrent ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function: Show English characters
|
||||
parameter:
|
||||
Xpoint :X coordinate
|
||||
Ypoint :Y coordinate
|
||||
Acsii_Char :To display the English characters
|
||||
Font :A structure pointer that displays a character size
|
||||
Color_Foreground : Select the foreground color
|
||||
Color_Background : Select the background color
|
||||
******************************************************************************/
|
||||
void Paint_DrawChar(uint16_t Xpoint, uint16_t Ypoint, const char Acsii_Char,
|
||||
sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background){
|
||||
uint16_t Page, Column;
|
||||
|
||||
if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
|
||||
Debug("Paint_DrawChar Input exceeds the normal display range\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t Char_Offset = (Acsii_Char - ' ') * Font->Height * (Font->Width / 8 + (Font->Width % 8 ? 1 : 0));
|
||||
const unsigned char *ptr = &Font->table[Char_Offset];
|
||||
|
||||
for (Page = 0; Page < Font->Height; Page ++ ) {
|
||||
for (Column = 0; Column < Font->Width; Column ++ ) {
|
||||
if (FONT_BACKGROUND == Color_Background) {
|
||||
if (*ptr & (0x80 >> (Column % 8)))
|
||||
Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Foreground);
|
||||
} else {
|
||||
if (*ptr & (0x80 >> (Column % 8))) {
|
||||
Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Foreground);
|
||||
} else {
|
||||
Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Background);
|
||||
}
|
||||
}
|
||||
if (Column % 8 == 7) ptr++;
|
||||
}
|
||||
if (Font->Width % 8 != 0)
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
void Paint_DrawIcon(uint16_t Xpoint, uint16_t Ypoint, const ICON_tpe icon,
|
||||
sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background){
|
||||
uint16_t Page, Column;
|
||||
|
||||
if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
|
||||
Debug("Paint_DrawIcon Input exceeds the normal display range\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t Char_Offset = (icon) * Font->Height * (Font->Width / 8 + (Font->Width % 8 ? 1 : 0));
|
||||
const unsigned char *ptr = &Font->table[Char_Offset];
|
||||
|
||||
for (Page = 0; Page < Font->Height; Page ++ ) {
|
||||
for (Column = 0; Column < Font->Width; Column ++ ) {
|
||||
if (FONT_BACKGROUND == Color_Background) {
|
||||
if (*ptr & (0x80 >> (Column % 8)))
|
||||
Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Foreground);
|
||||
} else {
|
||||
if (*ptr & (0x80 >> (Column % 8))) {
|
||||
Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Foreground);
|
||||
} else {
|
||||
Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Background);
|
||||
}
|
||||
}
|
||||
if (Column % 8 == 7) ptr++;
|
||||
}
|
||||
if (Font->Width % 8 != 0)
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
function: Display the string
|
||||
parameter:
|
||||
Xstart :X coordinate
|
||||
Ystart :Y coordinate
|
||||
pString :The first address of the English string to be displayed
|
||||
Font :A structure pointer that displays a character size
|
||||
Color_Foreground : Select the foreground color
|
||||
Color_Background : Select the background color
|
||||
******************************************************************************/
|
||||
void Paint_DrawString_EN(uint16_t Xstart, uint16_t Ystart, const char * pString,
|
||||
sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background){
|
||||
uint16_t Xpoint = Xstart;
|
||||
uint16_t Ypoint = Ystart;
|
||||
|
||||
if (Xstart > Paint.Width || Ystart > Paint.Height) {
|
||||
Debug("Paint_DrawString_EN Input exceeds the normal display range\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
while (* pString != '\0') {
|
||||
if ((Xpoint + Font->Width ) > Paint.Width ) {
|
||||
Xpoint = Xstart;
|
||||
Ypoint += Font->Height;
|
||||
}
|
||||
|
||||
if ((Ypoint + Font->Height ) > Paint.Height ) {
|
||||
Xpoint = Xstart;
|
||||
Ypoint = Ystart;
|
||||
}
|
||||
Paint_DrawChar(Xpoint, Ypoint, * pString, Font, Color_Background, Color_Foreground);
|
||||
|
||||
pString ++;
|
||||
Xpoint += Font->Width;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
function: Display nummber
|
||||
parameter:
|
||||
Xstart :X coordinate
|
||||
Ystart : Y coordinate
|
||||
Nummber : The number displayed
|
||||
Font :A structure pointer that displays a character size
|
||||
Color_Foreground : Select the foreground color
|
||||
Color_Background : Select the background color
|
||||
******************************************************************************/
|
||||
#define ARRAY_LEN 255
|
||||
void Paint_DrawIntUnit(uint16_t Xpoint, uint16_t Ypoint, int32_t Number,const char * pString, sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background){
|
||||
int16_t Str_Bit = 0, Unit_Bit = 0;
|
||||
uint8_t Str_Array[ARRAY_LEN] = {0};
|
||||
uint8_t *pStr = Str_Array;
|
||||
|
||||
if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
|
||||
Debug("Paint_DisNum Input exceeds the normal display range\r\n");
|
||||
return;
|
||||
}
|
||||
itoa(Number, (char*)Str_Array, 10);
|
||||
|
||||
while (Str_Array[Str_Bit] != '\0') {
|
||||
++Str_Bit;
|
||||
}
|
||||
|
||||
while (pString[Unit_Bit] != '\0') {
|
||||
Str_Array[Str_Bit] = pString[Unit_Bit];
|
||||
++Unit_Bit;
|
||||
++Str_Bit;
|
||||
}
|
||||
|
||||
Paint_DrawString_EN(Xpoint, Ypoint, (const char*)pStr, Font, Color_Background, Color_Foreground);
|
||||
}
|
||||
|
||||
void Paint_DrawFltUnit(uint16_t Xpoint, uint16_t Ypoint, float Number,const char * pString, sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background){
|
||||
int16_t Str_Bit = 0, Unit_Bit = 0;
|
||||
uint8_t Str_Array[ARRAY_LEN] = {0};
|
||||
uint8_t *pStr = Str_Array;
|
||||
|
||||
if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
|
||||
Debug("Paint_DisNum Input exceeds the normal display range\r\n");
|
||||
return;
|
||||
}
|
||||
dtostrf(Number, -4, 2, (char*)Str_Array);
|
||||
while (Str_Array[Str_Bit] != '\0') {
|
||||
++Str_Bit;
|
||||
}
|
||||
|
||||
while (pString[Unit_Bit] != '\0') {
|
||||
Str_Array[Str_Bit] = pString[Unit_Bit];
|
||||
++Unit_Bit;
|
||||
++Str_Bit;
|
||||
}
|
||||
|
||||
Paint_DrawString_EN(Xpoint, Ypoint, (const char*)pStr, Font, Color_Background, Color_Foreground);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
function: Display time
|
||||
parameter:
|
||||
Xstart :X coordinate
|
||||
Ystart : Y coordinate
|
||||
pTime : Time-related structures
|
||||
Font :A structure pointer that displays a character size
|
||||
Color_Foreground : Select the foreground color
|
||||
Color_Background : Select the background color
|
||||
******************************************************************************/
|
||||
void Paint_DrawTime(uint16_t Xstart, uint16_t Ystart, strDateTime *pTime, sFONT* Font,
|
||||
uint16_t Color_Foreground, uint16_t Color_Background){
|
||||
uint8_t value[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
|
||||
|
||||
uint16_t Dx = Font->Width;
|
||||
|
||||
//Write data into the cache
|
||||
Paint_DrawChar(Xstart , Ystart, value[pTime->hour / 10], Font, Color_Background, Color_Foreground);
|
||||
Paint_DrawChar(Xstart + Dx , Ystart, value[pTime->hour % 10], Font, Color_Background, Color_Foreground);
|
||||
Paint_DrawChar(Xstart + Dx + Dx / 4 + Dx / 2 , Ystart, ':' , Font, Color_Background, Color_Foreground);
|
||||
Paint_DrawChar(Xstart + Dx * 2 + Dx / 2 , Ystart, value[pTime->minute / 10] , Font, Color_Background, Color_Foreground);
|
||||
Paint_DrawChar(Xstart + Dx * 3 + Dx / 2 , Ystart, value[pTime->minute % 10] , Font, Color_Background, Color_Foreground);
|
||||
}
|
127
src/epd/epd_paint.h
Normal file
127
src/epd/epd_paint.h
Normal file
@ -0,0 +1,127 @@
|
||||
#ifndef __GUI_PAINT_H
|
||||
#define __GUI_PAINT_H
|
||||
|
||||
#include "debug.h"
|
||||
#include "epd_cfg.h"
|
||||
#include "fonts/fonts.h"
|
||||
#include "../time/time.h"
|
||||
|
||||
/**
|
||||
* Image attributes
|
||||
**/
|
||||
typedef struct {
|
||||
uint8_t *Image;
|
||||
uint16_t Width;
|
||||
uint16_t Height;
|
||||
uint16_t WidthMemory;
|
||||
uint16_t HeightMemory;
|
||||
uint16_t Color;
|
||||
uint16_t Rotate;
|
||||
uint16_t Mirror;
|
||||
uint16_t WidthByte;
|
||||
uint16_t HeightByte;
|
||||
uint16_t Scale;
|
||||
} PAINT;
|
||||
extern PAINT Paint;
|
||||
|
||||
/**
|
||||
* Display rotate
|
||||
**/
|
||||
#define ROTATE_0 0
|
||||
#define ROTATE_90 90
|
||||
#define ROTATE_180 180
|
||||
#define ROTATE_270 270
|
||||
|
||||
/**
|
||||
* Display Flip
|
||||
**/
|
||||
typedef enum {
|
||||
MIRROR_NONE = 0x00,
|
||||
MIRROR_HORIZONTAL = 0x01,
|
||||
MIRROR_VERTICAL = 0x02,
|
||||
MIRROR_ORIGIN = 0x03,
|
||||
} MIRROR_IMAGE;
|
||||
#define MIRROR_IMAGE_DFT MIRROR_NONE
|
||||
|
||||
/**
|
||||
* image color
|
||||
**/
|
||||
#define WHITE 0xFF
|
||||
#define BLACK 0x00
|
||||
#define RED BLACK
|
||||
|
||||
#define IMAGE_BACKGROUND WHITE
|
||||
#define FONT_FOREGROUND BLACK
|
||||
#define FONT_BACKGROUND WHITE
|
||||
|
||||
//4 Gray level
|
||||
#define GRAY1 0x03 //Blackest
|
||||
#define GRAY2 0x02
|
||||
#define GRAY3 0x01 //gray
|
||||
#define GRAY4 0x00 //white
|
||||
/**
|
||||
* The size of the point
|
||||
**/
|
||||
typedef enum {
|
||||
DOT_PIXEL_1X1 = 1, // 1 x 1
|
||||
DOT_PIXEL_2X2 , // 2 X 2
|
||||
DOT_PIXEL_3X3 , // 3 X 3
|
||||
DOT_PIXEL_4X4 , // 4 X 4
|
||||
DOT_PIXEL_5X5 , // 5 X 5
|
||||
DOT_PIXEL_6X6 , // 6 X 6
|
||||
DOT_PIXEL_7X7 , // 7 X 7
|
||||
DOT_PIXEL_8X8 , // 8 X 8
|
||||
} DOT_PIXEL;
|
||||
#define DOT_PIXEL_DFT DOT_PIXEL_1X1 //Default dot pilex
|
||||
|
||||
/**
|
||||
* Point size fill style
|
||||
**/
|
||||
typedef enum {
|
||||
DOT_FILL_AROUND = 1, // dot pixel 1 x 1
|
||||
DOT_FILL_RIGHTUP , // dot pixel 2 X 2
|
||||
} DOT_STYLE;
|
||||
#define DOT_STYLE_DFT DOT_FILL_AROUND //Default dot pilex
|
||||
|
||||
/**
|
||||
* Line style, solid or dashed
|
||||
**/
|
||||
typedef enum {
|
||||
LINE_STYLE_SOLID = 0,
|
||||
LINE_STYLE_DOTTED,
|
||||
} LINE_STYLE;
|
||||
|
||||
/**
|
||||
* Whether the graphic is filled
|
||||
**/
|
||||
typedef enum {
|
||||
DRAW_FILL_EMPTY = 0,
|
||||
DRAW_FILL_FULL,
|
||||
} DRAW_FILL;
|
||||
|
||||
|
||||
//init and Clear
|
||||
void Paint_NewImage(uint8_t *image, uint16_t Width, uint16_t Height, uint16_t Rotate, uint16_t Color);
|
||||
void Paint_SelectImage(uint8_t *image);
|
||||
void Paint_SetRotate(uint16_t Rotate);
|
||||
void Paint_SetMirroring(uint8_t mirror);
|
||||
void Paint_SetPixel(uint16_t Xpoint, uint16_t Ypoint, uint16_t Color);
|
||||
void Paint_SetScale(uint8_t scale);
|
||||
|
||||
void Paint_Clear(uint16_t Color);
|
||||
void Paint_ClearWindows(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint16_t Color);
|
||||
|
||||
//Drawing
|
||||
// void Paint_DrawPoint(uint16_t Xpoint, uint16_t Ypoint, uint16_t Color, DOT_PIXEL Dot_Pixel, DOT_STYLE Dot_FillWay);
|
||||
// void Paint_DrawLine(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint16_t Color, DOT_PIXEL Line_width, LINE_STYLE Line_Style);
|
||||
|
||||
//Display string
|
||||
void Paint_DrawChar(uint16_t Xstart, uint16_t Ystart, const char Acsii_Char, sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background);
|
||||
void Paint_DrawIcon(uint16_t Xpoint, uint16_t Ypoint, const ICON_tpe icon, sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background);
|
||||
void Paint_DrawString_EN(uint16_t Xstart, uint16_t Ystart, const char * pString, sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background);
|
||||
void Paint_DrawIntUnit(uint16_t Xpoint, uint16_t Ypoint, int32_t Number,const char * pString, sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background);
|
||||
void Paint_DrawFltUnit(uint16_t Xpoint, uint16_t Ypoint, float Number,const char * pString, sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background);
|
||||
void Paint_DrawTime(uint16_t Xstart, uint16_t Ystart, strDateTime *pTime, sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background);
|
||||
|
||||
|
||||
#endif
|
1384
src/epd/fonts/font12.cpp
Normal file
1384
src/epd/fonts/font12.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1764
src/epd/fonts/font16.cpp
Normal file
1764
src/epd/fonts/font16.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2142
src/epd/fonts/font20.cpp
Normal file
2142
src/epd/fonts/font20.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2520
src/epd/fonts/font24.cpp
Normal file
2520
src/epd/fonts/font24.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2208
src/epd/fonts/font45.cpp
Normal file
2208
src/epd/fonts/font45.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1004
src/epd/fonts/font8.cpp
Normal file
1004
src/epd/fonts/font8.cpp
Normal file
File diff suppressed because it is too large
Load Diff
90
src/epd/fonts/fonts.h
Normal file
90
src/epd/fonts/fonts.h
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file fonts.h
|
||||
* @author MCD Application Team
|
||||
* @version V1.0.0
|
||||
* @date 18-February-2014
|
||||
* @brief Header for fonts.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __FONTS_H
|
||||
#define __FONTS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <stdint.h>
|
||||
|
||||
//ASCII
|
||||
typedef struct _tFont
|
||||
{
|
||||
const uint8_t *table;
|
||||
uint16_t Width;
|
||||
uint16_t Height;
|
||||
|
||||
} sFONT;
|
||||
|
||||
extern sFONT Font45;
|
||||
extern sFONT Font24;
|
||||
extern sFONT Font20;
|
||||
extern sFONT Font16;
|
||||
extern sFONT Font12;
|
||||
extern sFONT Font8;
|
||||
|
||||
extern sFONT FontIcon;
|
||||
|
||||
|
||||
typedef enum {
|
||||
ICON_LOGO = 0,
|
||||
ICON_WARN,
|
||||
ICON_TEMPERATURE, ICON_DROP, ICON_SCALE, ICON_POLUTION,
|
||||
|
||||
ICON_SUN,
|
||||
|
||||
ICON_CLOUD, ICON_CLOUD_RAIN, ICON_CLOUD_SNOW,
|
||||
ICON_CLOUD_THUNDER, ICON_CLOUD_SUN,
|
||||
|
||||
|
||||
ICON_SUNSET, ICON_SUNRISE,
|
||||
} ICON_tpe;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FONTS_H */
|
||||
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
1124
src/epd/fonts/icons.cpp
Normal file
1124
src/epd/fonts/icons.cpp
Normal file
File diff suppressed because it is too large
Load Diff
633
src/epd/icon.h
Normal file
633
src/epd/icon.h
Normal file
@ -0,0 +1,633 @@
|
||||
/* GIMP header image file format (INDEXED): /home/sora/files/sora/metesp/metesp/src/epd/icon.h */
|
||||
|
||||
static unsigned int width = 72;
|
||||
static unsigned int height = 72;
|
||||
|
||||
/* Call this macro repeatedly. After each use, the pixel data can be extracted */
|
||||
|
||||
#define HEADER_PIXEL(data,pixel) {\
|
||||
pixel[0] = header_data_cmap[(unsigned char)data[0]][0]; \
|
||||
pixel[1] = header_data_cmap[(unsigned char)data[0]][1]; \
|
||||
pixel[2] = header_data_cmap[(unsigned char)data[0]][2]; \
|
||||
data ++; }
|
||||
|
||||
static unsigned char header_data_cmap[256][3] = {
|
||||
{ 0, 0, 0},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255},
|
||||
{255,255,255}
|
||||
};
|
||||
static unsigned char header_data[] = {
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,
|
||||
1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,
|
||||
1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,
|
||||
1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,
|
||||
0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,
|
||||
0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,0,0,0,0,1,1,1,1,1,
|
||||
0,0,1,1,1,1,0,0,1,1,1,1,1,1,0,0,
|
||||
0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,0,0,0,0,1,1,1,0,
|
||||
0,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,1,1,0,0,0,1,1,0,
|
||||
0,1,1,1,1,1,1,0,0,1,1,0,0,0,1,1,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,
|
||||
1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,0,0,1,1,0,0,0,0,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,
|
||||
1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
|
||||
0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
|
||||
0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
|
||||
0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,
|
||||
1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,0,0,0,0,0,0,1,1,1,1,1,0,0,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,
|
||||
1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,0,0,0,1,1,1,1,1,1,0,0,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,
|
||||
1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,0,0,1,1,1,1,1,0,0,0,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,
|
||||
1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,0,1,1,0,0,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
|
||||
1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,0,0,1,0,0,0,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
|
||||
0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
|
||||
0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
|
||||
0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
|
||||
0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
|
||||
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,0,
|
||||
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,0,0,1,1,0,0,0,0,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,
|
||||
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,
|
||||
0,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
|
||||
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,
|
||||
0,0,0,1,1,1,1,1,
|
||||
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
|
||||
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,
|
||||
0,0,0,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,
|
||||
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,
|
||||
0,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,0,
|
||||
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,0,0,1,1,0,0,0,0,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
|
||||
0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
|
||||
0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
|
||||
0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
|
||||
0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
|
||||
0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
|
||||
1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,0,0,1,0,0,0,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,
|
||||
1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,0,0,1,1,1,1,1,0,0,0,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,
|
||||
1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,0,0,0,1,1,1,1,1,1,0,0,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,
|
||||
1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,0,0,0,0,0,0,1,1,1,1,1,0,0,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
|
||||
0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
|
||||
0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
|
||||
0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,0,0,1,1,0,0,0,0,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,
|
||||
1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,0,0,1,1,1,1,0,0,0,0,0,
|
||||
0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,
|
||||
1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,1,1,0,0,0,1,1,0,
|
||||
0,1,1,1,1,1,1,0,0,1,1,0,0,0,1,1,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,0,0,0,0,1,1,1,0,
|
||||
0,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,0,0,0,1,1,1,1,1,1,
|
||||
0,0,1,1,1,1,0,0,1,1,1,1,1,1,0,0,
|
||||
0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,
|
||||
0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,
|
||||
0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,
|
||||
1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,
|
||||
1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,
|
||||
1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,
|
||||
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1
|
||||
};
|
166
src/influxdb/influx.h
Normal file
166
src/influxdb/influx.h
Normal file
@ -0,0 +1,166 @@
|
||||
#ifndef TG_INFLUX_H
|
||||
#define TG_INFLUX_H
|
||||
|
||||
#define DEVICE "ESP32"
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
#include <InfluxDbClient.h>
|
||||
|
||||
#include "../sensor/sensor.h"
|
||||
#include "../owm/owm.h"
|
||||
|
||||
const char* cert = "-----BEGIN CERTIFICATE-----\n\
|
||||
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n\
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n\
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n\
|
||||
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n\
|
||||
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n\
|
||||
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n\
|
||||
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n\
|
||||
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n\
|
||||
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n\
|
||||
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n\
|
||||
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n\
|
||||
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n\
|
||||
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n\
|
||||
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n\
|
||||
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n\
|
||||
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n\
|
||||
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n\
|
||||
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n\
|
||||
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n\
|
||||
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n\
|
||||
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n\
|
||||
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n\
|
||||
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n\
|
||||
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n\
|
||||
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n\
|
||||
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n\
|
||||
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n\
|
||||
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n\
|
||||
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n\
|
||||
-----END CERTIFICATE-----\n\
|
||||
";
|
||||
|
||||
|
||||
class Influx {
|
||||
|
||||
public:
|
||||
Influx(Sensor* _sensor, OWM* _owm0, OWM* _owm1): sensor(_sensor), owm0(_owm0), owm1(_owm1) {}
|
||||
|
||||
void check(){
|
||||
if (client.validateConnection()) {
|
||||
Serial.print("Connected to InfluxDB: ");
|
||||
Serial.println(client.getServerUrl());
|
||||
} else {
|
||||
Serial.print("InfluxDB connection failed: ");
|
||||
Serial.println(client.getLastErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
void record(){
|
||||
if(owm0) record_weather(owm0);
|
||||
if(owm1) record_weather(owm1);
|
||||
if(sensor) record_local();
|
||||
}
|
||||
|
||||
void record(bool w, bool s){
|
||||
if(owm0 && w) record_weather(owm0);
|
||||
if(owm1 && w) record_weather(owm1);
|
||||
if(sensor && s) record_local();
|
||||
}
|
||||
|
||||
|
||||
void record_local(){
|
||||
if(!sensor) return;
|
||||
dp.clearFields();
|
||||
dp.clearTags();
|
||||
dp.addTag("device", "WESP0");
|
||||
dp.addTag("location", "local");
|
||||
|
||||
dp.addField("temperature", sensor->temp);
|
||||
dp.addField("pressure", sensor->pres);
|
||||
dp.addField("humidity", sensor->temp);
|
||||
dp.addField("heat_index", sensor->heatidx);
|
||||
|
||||
dp.addField("light", sensor->light);
|
||||
dp.addField("uv", sensor->uv);
|
||||
dp.addField("uvi", sensor->uvi);
|
||||
|
||||
|
||||
dp.addField("light_full", sensor->light_full);
|
||||
dp.addField("light_vis", sensor->light_vis);
|
||||
dp.addField("light_ir", sensor->light_ir);
|
||||
dp.addField("light_lux", sensor->light_lux);
|
||||
|
||||
dp.addField("voc", sensor->voci);
|
||||
|
||||
dp.addField("pm10_standard", sensor->pmd.pm10_standard);
|
||||
dp.addField("pm25_standard", sensor->pmd.pm25_standard);
|
||||
dp.addField("pm100_standard", sensor->pmd.pm100_standard);
|
||||
dp.addField("pm10_env", sensor->pmd.pm10_env);
|
||||
dp.addField("pm25_env", sensor->pmd.pm25_env);
|
||||
dp.addField("pm100_env", sensor->pmd.pm100_env);
|
||||
dp.addField("particles_03um", sensor->pmd.particles_03um);
|
||||
dp.addField("particles_05um", sensor->pmd.particles_05um);
|
||||
dp.addField("particles_10um", sensor->pmd.particles_10um);
|
||||
dp.addField("particles_25um", sensor->pmd.particles_25um);
|
||||
dp.addField("particles_50um", sensor->pmd.particles_50um);
|
||||
dp.addField("particles_100um", sensor->pmd.particles_100um);
|
||||
|
||||
client.writePoint(dp);
|
||||
}
|
||||
|
||||
void record_weather(OWM* owm){
|
||||
if(!owm) return;
|
||||
if(!owm->valid_weather) return;
|
||||
|
||||
JsonObject weather_0 = owm->weather["weather"][0];
|
||||
JsonObject weather_main = owm->weather["main"];
|
||||
JsonObject weather_sys = owm->weather["sys"];
|
||||
if(!weather_0 || !weather_main || !weather_sys ) return;
|
||||
|
||||
dp.clearFields();
|
||||
dp.clearTags();
|
||||
dp.addTag("device", "WESP0");
|
||||
dp.addTag("location", owm->location);
|
||||
|
||||
dp.addField("temperature", float(weather_main["temp"]));
|
||||
dp.addField("temperature_feel",float(weather_main["feels_like"]));
|
||||
dp.addField("pressure",int32_t(weather_main["pressure"]));
|
||||
dp.addField("humidity",int32_t(weather_main["humidity"]));
|
||||
|
||||
|
||||
JsonObject weather_wind = owm->weather["wind"];
|
||||
dp.addField("wind_speed",weather_wind?float(weather_wind["speed"]):0.0);
|
||||
dp.addField("wind_dir",weather_wind?float(weather_wind["deg"]):0.0);
|
||||
dp.addField("wind_gust",weather_wind?float(weather_wind["gust"]):0.0);
|
||||
|
||||
dp.addField("sunrise", uint64_t(weather_sys["sunrise"]));
|
||||
dp.addField("sunset",uint64_t(weather_sys["sunset"]));
|
||||
dp.addField("suntime",uint64_t(weather_sys["sunset"])-uint64_t(weather_sys["sunrise"]));
|
||||
|
||||
|
||||
JsonObject weather_rain = owm->weather["rain"];
|
||||
dp.addField("precipitation_rain_1h",weather_rain?float(weather_rain["1h"]):0.0);
|
||||
dp.addField("precipitation_rain_3h",weather_rain?float(weather_rain["3h"]):0.0);
|
||||
|
||||
JsonObject weather_snow = owm->weather["snow"];
|
||||
dp.addField("precipitation_snow_1h",weather_snow?float(weather_snow["1h"]):0.0);
|
||||
dp.addField("precipitation_snow_3h",weather_snow?float(weather_snow["3h"]):0.0);
|
||||
|
||||
client.writePoint(dp);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
OWM* owm0;
|
||||
OWM* owm1;
|
||||
Sensor* sensor;
|
||||
|
||||
InfluxDBClient client = InfluxDBClient(INFLUXDB_URL, INFLUXDB_ORG, INFLUXDB_BUCKET, INFLUXDB_TOKEN, cert);
|
||||
Point dp = Point("environment");
|
||||
};
|
||||
|
||||
#endif
|
225
src/ntpt/ntp.cpp
Normal file
225
src/ntpt/ntp.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
#include "ntp.h"
|
||||
|
||||
#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) )
|
||||
|
||||
#define SEC_TO_MS 1000
|
||||
#define RECV_TIMEOUT_DEFATUL 1 // 1 second
|
||||
#define SEND_INTRVL_DEFAULT 1 // 1 second
|
||||
#define MAX_SEND_INTERVAL 60 // 60 seconds
|
||||
#define MAC_RECV_TIMEOUT 60 // 60 seconds
|
||||
|
||||
const int NTP_PACKET_SIZE = 48;
|
||||
byte _packetBuffer[ NTP_PACKET_SIZE];
|
||||
static const uint8_t _monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
float _timeZone=0.0;
|
||||
String _NTPserver="";
|
||||
|
||||
// NTPserver is the name of the NTPserver
|
||||
|
||||
bool NTPtime::setSendInterval(unsigned long _sendInterval_) {
|
||||
bool retVal = false;
|
||||
if(_sendInterval_ <= MAX_SEND_INTERVAL) {
|
||||
_sendInterval = _sendInterval_ * SEC_TO_MS;
|
||||
retVal = true;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool NTPtime::setRecvTimeout(unsigned long _recvTimeout_) {
|
||||
bool retVal = false;
|
||||
if(_recvTimeout_ <= MAC_RECV_TIMEOUT) {
|
||||
_recvTimeout = _recvTimeout_ * SEC_TO_MS;
|
||||
retVal = true;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
NTPtime::NTPtime(String NTPserver) {
|
||||
_NTPserver = NTPserver;
|
||||
_sendPhase = true;
|
||||
_sentTime = 0;
|
||||
_sendInterval = SEND_INTRVL_DEFAULT * SEC_TO_MS;
|
||||
_recvTimeout = RECV_TIMEOUT_DEFATUL * SEC_TO_MS;
|
||||
}
|
||||
|
||||
// Converts a unix time stamp to a strDateTime structure
|
||||
strDateTime NTPtime::ConvertUnixTimestamp( unsigned long _tempTimeStamp) {
|
||||
strDateTime _tempDateTime;
|
||||
uint8_t _year, _month, _monthLength;
|
||||
uint32_t _time;
|
||||
unsigned long _days;
|
||||
|
||||
_time = (uint32_t)_tempTimeStamp;
|
||||
_tempDateTime.second = _time % 60;
|
||||
_time /= 60; // now it is minutes
|
||||
_tempDateTime.minute = _time % 60;
|
||||
_time /= 60; // now it is hours
|
||||
_tempDateTime.hour = _time % 24;
|
||||
_time /= 24; // now it is _days
|
||||
_tempDateTime.dayofWeek = ((_time + 4) % 7) + 1; // Sunday is day 1
|
||||
|
||||
_year = 0;
|
||||
_days = 0;
|
||||
while ((unsigned)(_days += (LEAP_YEAR(_year) ? 366 : 365)) <= _time) {
|
||||
_year++;
|
||||
}
|
||||
_tempDateTime.year = _year; // year is offset from 1970
|
||||
|
||||
_days -= LEAP_YEAR(_year) ? 366 : 365;
|
||||
_time -= _days; // now it is days in this year, starting at 0
|
||||
|
||||
_days = 0;
|
||||
_month = 0;
|
||||
_monthLength = 0;
|
||||
for (_month = 0; _month < 12; _month++) {
|
||||
if (_month == 1) { // february
|
||||
if (LEAP_YEAR(_year)) {
|
||||
_monthLength = 29;
|
||||
} else {
|
||||
_monthLength = 28;
|
||||
}
|
||||
} else {
|
||||
_monthLength = _monthDays[_month];
|
||||
}
|
||||
|
||||
if (_time >= _monthLength) {
|
||||
_time -= _monthLength;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
_tempDateTime.month = _month + 1; // jan is month 1
|
||||
_tempDateTime.day = _time + 1; // day of month
|
||||
_tempDateTime.year += 1970;
|
||||
|
||||
return _tempDateTime;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summertime calculates the daylight saving time for middle Europe. Input: Unixtime in UTC
|
||||
//
|
||||
boolean NTPtime::summerTime(unsigned long _timeStamp ) {
|
||||
|
||||
strDateTime _tempDateTime;
|
||||
_tempDateTime = ConvertUnixTimestamp(_timeStamp);
|
||||
|
||||
if (_tempDateTime.month < 3 || _tempDateTime.month > 10) return false; // keine Sommerzeit in Jan, Feb, Nov, Dez
|
||||
if (_tempDateTime.month > 3 && _tempDateTime.month < 10) return true; // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep
|
||||
if (_tempDateTime.month == 3 && (_tempDateTime.hour + 24 * _tempDateTime.day) >= (3 + 24 * (31 - (5 * _tempDateTime.year / 4 + 4) % 7)) || _tempDateTime.month == 10 && (_tempDateTime.hour + 24 * _tempDateTime.day) < (3 + 24 * (31 - (5 * _tempDateTime.year / 4 + 1) % 7)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean NTPtime::daylightSavingTime(unsigned long _timeStamp) {
|
||||
|
||||
strDateTime _tempDateTime;
|
||||
_tempDateTime = ConvertUnixTimestamp(_timeStamp);
|
||||
|
||||
if (_tempDateTime.month < 3 || _tempDateTime.month > 11) return false; //January, february, and december are out.
|
||||
if (_tempDateTime.month > 3 && _tempDateTime.month < 11) return true; //April to October are in
|
||||
int previousSunday = _tempDateTime.day - (_tempDateTime.dayofWeek - 1); // dow Sunday input was 1,
|
||||
|
||||
// -------------------- March ---------------------------------------
|
||||
//In march, we are DST if our previous Sunday was = to or after the 8th.
|
||||
if (_tempDateTime.month == 3 ) { // in march, if previous Sunday is after the 8th, is DST
|
||||
// unless Sunday and hour < 2am
|
||||
if ( previousSunday >= 8 ) { // Sunday = 1
|
||||
// return true if day > 14 or (dow == 1 and hour >= 2)
|
||||
return ((_tempDateTime.day > 14) ||
|
||||
((_tempDateTime.dayofWeek == 1 && _tempDateTime.hour >= 2) || _tempDateTime.dayofWeek > 1));
|
||||
} // end if ( previousSunday >= 8 && _dateTime.dayofWeek > 0 )
|
||||
else
|
||||
{
|
||||
// previousSunday has to be < 8 to get here
|
||||
//return (previousSunday < 8 && (_tempDateTime.dayofWeek - 1) = 0 && _tempDateTime.hour >= 2)
|
||||
return false;
|
||||
} // end else
|
||||
} // end if (_tempDateTime.month == 3 )
|
||||
|
||||
// ------------------------------- November -------------------------------
|
||||
|
||||
// gets here only if month = November
|
||||
//In november we must be before the first Sunday to be dst.
|
||||
//That means the previous Sunday must be before the 2nd.
|
||||
if (previousSunday < 1){
|
||||
// is not true for Sunday after 2am or any day after 1st Sunday any time
|
||||
return ((_tempDateTime.dayofWeek == 1 && _tempDateTime.hour < 2) || (_tempDateTime.dayofWeek > 1));
|
||||
//return true;
|
||||
}else{
|
||||
// return false unless after first wk and dow = Sunday and hour < 2
|
||||
return (_tempDateTime.day <8 && _tempDateTime.dayofWeek == 1 && _tempDateTime.hour < 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned long NTPtime::adjustTimeZone(unsigned long _timeStamp, float _timeZone, byte _DayLightSaving) {
|
||||
strDateTime _tempDateTime;
|
||||
_timeStamp += (unsigned long)(_timeZone * 3600.0); // adjust timezone
|
||||
if (_DayLightSaving ==1 && summerTime(_timeStamp)) _timeStamp += 3600; // European Summer time
|
||||
if (_DayLightSaving ==2 && daylightSavingTime(_timeStamp)) _timeStamp += 3600; // US daylight time
|
||||
return _timeStamp;
|
||||
}
|
||||
|
||||
|
||||
strDateTime NTPtime::getNTPtime(float _timeZone, boolean _DayLightSaving) {
|
||||
int cb;
|
||||
strDateTime _dateTime;
|
||||
unsigned long _unixTime = 0;
|
||||
_dateTime.valid = false;
|
||||
unsigned long _currentTimeStamp;
|
||||
|
||||
if (_sendPhase) {
|
||||
if (_sentTime && ((millis() - _sentTime) < _sendInterval)) {
|
||||
return _dateTime;
|
||||
}
|
||||
|
||||
_sendPhase = false;
|
||||
UDPNTPClient.begin(1337); // Port for NTP receive
|
||||
|
||||
memset(_packetBuffer, 0, NTP_PACKET_SIZE);
|
||||
_packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
_packetBuffer[1] = 0; // Stratum, or type of clock
|
||||
_packetBuffer[2] = 6; // Polling Interval
|
||||
_packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
_packetBuffer[12] = 49;
|
||||
_packetBuffer[13] = 0x4E;
|
||||
_packetBuffer[14] = 49;
|
||||
_packetBuffer[15] = 52;
|
||||
UDPNTPClient.beginPacket(_NTPserver.c_str(), 123);
|
||||
UDPNTPClient.write(_packetBuffer, NTP_PACKET_SIZE);
|
||||
UDPNTPClient.endPacket();
|
||||
|
||||
_sentTime = millis();
|
||||
} else {
|
||||
cb = UDPNTPClient.parsePacket();
|
||||
if (cb == 0) {
|
||||
if ((millis() - _sentTime) > _recvTimeout) {
|
||||
_sendPhase = true;
|
||||
_sentTime = 0;
|
||||
}
|
||||
} else {
|
||||
|
||||
UDPNTPClient.read(_packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
|
||||
unsigned long highWord = word(_packetBuffer[40], _packetBuffer[41]);
|
||||
unsigned long lowWord = word(_packetBuffer[42], _packetBuffer[43]);
|
||||
unsigned long secsSince1900 = highWord << 16 | lowWord;
|
||||
const unsigned long seventyYears = 2208988800UL;
|
||||
_unixTime = secsSince1900 - seventyYears;
|
||||
if (_unixTime > 0) {
|
||||
_currentTimeStamp = adjustTimeZone(_unixTime, _timeZone, _DayLightSaving);
|
||||
_dateTime = ConvertUnixTimestamp(_currentTimeStamp);
|
||||
_dateTime.valid = true;
|
||||
} else
|
||||
_dateTime.valid = false;
|
||||
|
||||
_sendPhase = true;
|
||||
}
|
||||
}
|
||||
|
||||
return _dateTime;
|
||||
}
|
28
src/ntpt/ntp.h
Normal file
28
src/ntpt/ntp.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef NTPtime_h
|
||||
#define NTPtime_h
|
||||
|
||||
#include <WiFiUdp.h>
|
||||
#include "../time/time.h"
|
||||
|
||||
class NTPtime {
|
||||
public:
|
||||
NTPtime(String NTPtime);
|
||||
strDateTime getNTPtime(float _timeZone, boolean _DayLightSaving);
|
||||
bool setSendInterval(unsigned long _sendInterval); // in seconds
|
||||
bool setRecvTimeout(unsigned long _recvTimeout); // in seconds
|
||||
|
||||
|
||||
static boolean summerTime(unsigned long _timeStamp );
|
||||
static strDateTime ConvertUnixTimestamp( unsigned long _tempTimeStamp);
|
||||
static boolean daylightSavingTime(unsigned long _timeStamp);
|
||||
static unsigned long adjustTimeZone(unsigned long _timeStamp, float _timeZone, byte _DayLightSavingSaving);
|
||||
|
||||
private:
|
||||
bool _sendPhase;
|
||||
unsigned long _sentTime;
|
||||
unsigned long _sendInterval;
|
||||
unsigned long _recvTimeout;
|
||||
|
||||
WiFiUDP UDPNTPClient;
|
||||
};
|
||||
#endif
|
93
src/owm/owm.h
Normal file
93
src/owm/owm.h
Normal file
@ -0,0 +1,93 @@
|
||||
#ifndef OWM_H
|
||||
#define OWM_H
|
||||
|
||||
#include <HTTPClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
|
||||
#define OPENWEATHER_URL(loc, api) ("https://api.openweathermap.org/data/2.5/weather?q=" + loc + "&appid=" + api + "&units=metric")
|
||||
|
||||
|
||||
class OWM{
|
||||
public:
|
||||
OWM(){};
|
||||
OWM(String l,String k) : location(l), key(k){}
|
||||
|
||||
StaticJsonDocument<1024> weather;
|
||||
bool valid_weather = false;
|
||||
|
||||
bool update(){
|
||||
String response = httpGETRequest(OPENWEATHER_URL(location,key).c_str());
|
||||
DeserializationError error = deserializeJson(weather, response);
|
||||
|
||||
if (error) {
|
||||
valid_weather = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(weather["weather"]==NULL ||weather["main"]==NULL ||
|
||||
weather["wind"]==NULL || weather["sys"]==NULL ){
|
||||
valid_weather = false;
|
||||
return false;
|
||||
}
|
||||
valid_weather = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
String location;
|
||||
private:
|
||||
String key;
|
||||
|
||||
String httpGETRequest(const char* serverName) {
|
||||
HTTPClient http;
|
||||
http.begin(serverName,root_ca);
|
||||
int httpResponseCode = http.GET();
|
||||
String payload = "{}";
|
||||
if (httpResponseCode == HTTP_CODE_OK) {
|
||||
payload = http.getString();
|
||||
}
|
||||
http.end();
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
const char* root_ca= \
|
||||
" -----BEGIN CERTIFICATE-----\n\
|
||||
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB\n\
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\n\
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\n\
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw\n\
|
||||
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV\n\
|
||||
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\n\
|
||||
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy\n\
|
||||
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n\
|
||||
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B\n\
|
||||
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY\n\
|
||||
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/\n\
|
||||
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2\n\
|
||||
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT\n\
|
||||
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6\n\
|
||||
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT\n\
|
||||
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l\n\
|
||||
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee\n\
|
||||
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE\n\
|
||||
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd\n\
|
||||
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G\n\
|
||||
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF\n\
|
||||
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO\n\
|
||||
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3\n\
|
||||
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs\n\
|
||||
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR\n\
|
||||
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze\n\
|
||||
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ\n\
|
||||
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/\n\
|
||||
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB\n\
|
||||
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB\n\
|
||||
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG\n\
|
||||
jjxDah2nGN59PRbxYvnKkKj9\n\
|
||||
-----END CERTIFICATE-----\n";
|
||||
|
||||
};
|
||||
|
||||
#endif
|
303
src/sensor/dev/bme280.cpp
Normal file
303
src/sensor/dev/bme280.cpp
Normal file
@ -0,0 +1,303 @@
|
||||
#include "bme280.h"
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool BME280::Initialize(){
|
||||
bool success(true);
|
||||
|
||||
success &= ReadChipID();
|
||||
|
||||
if(success){
|
||||
success &= ReadTrim();
|
||||
//InitializeFilter(); //If Filter ON
|
||||
WriteSettings();
|
||||
}
|
||||
m_initialized = success;
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
bool BME280::ReadChipID(){
|
||||
uint8_t id[1];
|
||||
|
||||
ReadRegister(ID_ADDR, &id[0], 1);
|
||||
|
||||
switch(id[0]){
|
||||
case ChipModel_BME280:
|
||||
m_chip_model = ChipModel_BME280;
|
||||
break;
|
||||
case ChipModel_BMP280:
|
||||
m_chip_model = ChipModel_BMP280;
|
||||
break;
|
||||
default:
|
||||
m_chip_model = ChipModel_UNKNOWN;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
void BME280::WriteSettings(){
|
||||
// ctrl_hum register. (ctrl_hum[2:0] = Humidity oversampling rate.)
|
||||
uint8_t ctrlHum = (uint8_t)OSR_X1;
|
||||
// ctrl_meas register. (ctrl_meas[7:5] = temperature oversampling rate, ctrl_meas[4:2] = pressure oversampling rate, ctrl_meas[1:0] = mode.)
|
||||
uint8_t ctrlMeas = ((uint8_t)OSR_X1 << 5) | ((uint8_t)OSR_X1 << 2) | (uint8_t)Mode_Forced;
|
||||
// config register. (config[7:5] = standby time, config[4:2] = filter, ctrl_meas[0] = spi enable.)
|
||||
uint8_t config = ((uint8_t)StandbyTime_1000ms << 5) | ((uint8_t)Filter_Off << 2) | 0;
|
||||
|
||||
WriteRegister(CTRL_HUM_ADDR, ctrlHum);
|
||||
WriteRegister(CTRL_MEAS_ADDR, ctrlMeas);
|
||||
WriteRegister(CONFIG_ADDR, config);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool BME280::begin(){
|
||||
bool success = Initialize();
|
||||
success &= m_initialized;
|
||||
return success;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
bool BME280::reset(){
|
||||
WriteRegister(RESET_ADDR, RESET_VALUE);
|
||||
delay(2); //max. startup time according to datasheet
|
||||
return(begin());
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
bool BME280::ReadTrim(){
|
||||
uint8_t ord(0);
|
||||
bool success = true;
|
||||
|
||||
// Temp. Dig
|
||||
success &= ReadRegister(TEMP_DIG_ADDR, &m_dig[ord], TEMP_DIG_LENGTH);
|
||||
ord += TEMP_DIG_LENGTH;
|
||||
|
||||
// Pressure Dig
|
||||
success &= ReadRegister(PRESS_DIG_ADDR, &m_dig[ord], PRESS_DIG_LENGTH);
|
||||
ord += PRESS_DIG_LENGTH;
|
||||
|
||||
// Humidity Dig 1
|
||||
success &= ReadRegister(HUM_DIG_ADDR1, &m_dig[ord], HUM_DIG_ADDR1_LENGTH);
|
||||
ord += HUM_DIG_ADDR1_LENGTH;
|
||||
|
||||
// Humidity Dig 2
|
||||
success &= ReadRegister(HUM_DIG_ADDR2, &m_dig[ord], HUM_DIG_ADDR2_LENGTH);
|
||||
ord += HUM_DIG_ADDR2_LENGTH;
|
||||
|
||||
#ifdef DEBUG_ON
|
||||
Serial.print("Dig: ");
|
||||
for(int i = 0; i < 32; ++i){
|
||||
Serial.print(m_dig[i], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
return success && ord == DIG_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool BME280::ReadData(int32_t data[SENSOR_DATA_LENGTH]){
|
||||
bool success;
|
||||
uint8_t buffer[SENSOR_DATA_LENGTH];
|
||||
|
||||
WriteSettings(); //IF Forced Mode
|
||||
|
||||
success = ReadRegister(PRESS_ADDR, buffer, SENSOR_DATA_LENGTH);
|
||||
|
||||
for(int i = 0; i < SENSOR_DATA_LENGTH; ++i){
|
||||
data[i] = static_cast<int32_t>(buffer[i]);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
float BME280::CalculateTemperature(int32_t raw,int32_t& t_fine){
|
||||
// Code based on calibration algorthim provided by Bosch.
|
||||
int32_t var1, var2, final;
|
||||
uint16_t dig_T1 = (m_dig[1] << 8) | m_dig[0];
|
||||
int16_t dig_T2 = (m_dig[3] << 8) | m_dig[2];
|
||||
int16_t dig_T3 = (m_dig[5] << 8) | m_dig[4];
|
||||
var1 = ((((raw >> 3) - ((int32_t)dig_T1 << 1))) * ((int32_t)dig_T2)) >> 11;
|
||||
var2 = (((((raw >> 4) - ((int32_t)dig_T1)) * ((raw >> 4) - ((int32_t)dig_T1))) >> 12) * ((int32_t)dig_T3)) >> 14;
|
||||
t_fine = var1 + var2;
|
||||
final = (t_fine * 5 + 128) >> 8;
|
||||
return final/100.0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
float BME280::CalculateHumidity
|
||||
(
|
||||
int32_t raw,
|
||||
int32_t t_fine
|
||||
)
|
||||
{
|
||||
// Code based on calibration algorthim provided by Bosch.
|
||||
int32_t var1;
|
||||
uint8_t dig_H1 = m_dig[24];
|
||||
int16_t dig_H2 = (m_dig[26] << 8) | m_dig[25];
|
||||
uint8_t dig_H3 = m_dig[27];
|
||||
int16_t dig_H4 = ((int8_t)m_dig[28] * 16) | (0x0F & m_dig[29]);
|
||||
int16_t dig_H5 = ((int8_t)m_dig[30] * 16) | ((m_dig[29] >> 4) & 0x0F);
|
||||
int8_t dig_H6 = m_dig[31];
|
||||
|
||||
var1 = (t_fine - ((int32_t)76800));
|
||||
var1 = (((((raw << 14) - (((int32_t)dig_H4) << 20) - (((int32_t)dig_H5) * var1)) +
|
||||
((int32_t)16384)) >> 15) * (((((((var1 * ((int32_t)dig_H6)) >> 10) * (((var1 *
|
||||
((int32_t)dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) *
|
||||
((int32_t)dig_H2) + 8192) >> 14));
|
||||
var1 = (var1 - (((((var1 >> 15) * (var1 >> 15)) >> 7) * ((int32_t)dig_H1)) >> 4));
|
||||
var1 = (var1 < 0 ? 0 : var1);
|
||||
var1 = (var1 > 419430400 ? 419430400 : var1);
|
||||
return ((uint32_t)(var1 >> 12))/1024.0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
float BME280::CalculatePressure(int32_t raw,int32_t t_fine,PresUnit unit){
|
||||
// Code based on calibration algorthim provided by Bosch.
|
||||
int64_t var1, var2, pressure;
|
||||
float final;
|
||||
|
||||
uint16_t dig_P1 = (m_dig[7] << 8) | m_dig[6];
|
||||
int16_t dig_P2 = (m_dig[9] << 8) | m_dig[8];
|
||||
int16_t dig_P3 = (m_dig[11] << 8) | m_dig[10];
|
||||
int16_t dig_P4 = (m_dig[13] << 8) | m_dig[12];
|
||||
int16_t dig_P5 = (m_dig[15] << 8) | m_dig[14];
|
||||
int16_t dig_P6 = (m_dig[17] << 8) | m_dig[16];
|
||||
int16_t dig_P7 = (m_dig[19] << 8) | m_dig[18];
|
||||
int16_t dig_P8 = (m_dig[21] << 8) | m_dig[20];
|
||||
int16_t dig_P9 = (m_dig[23] << 8) | m_dig[22];
|
||||
|
||||
var1 = (int64_t)t_fine - 128000;
|
||||
var2 = var1 * var1 * (int64_t)dig_P6;
|
||||
var2 = var2 + ((var1 * (int64_t)dig_P5) << 17);
|
||||
var2 = var2 + (((int64_t)dig_P4) << 35);
|
||||
var1 = ((var1 * var1 * (int64_t)dig_P3) >> 8) + ((var1 * (int64_t)dig_P2) << 12);
|
||||
var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)dig_P1) >> 33;
|
||||
if (var1 == 0) { return NAN; } // Don't divide by zero.
|
||||
pressure = 1048576 - raw;
|
||||
pressure = (((pressure << 31) - var2) * 3125)/var1;
|
||||
var1 = (((int64_t)dig_P9) * (pressure >> 13) * (pressure >> 13)) >> 25;
|
||||
var2 = (((int64_t)dig_P8) * pressure) >> 19;
|
||||
pressure = ((pressure + var1 + var2) >> 8) + (((int64_t)dig_P7) << 4);
|
||||
|
||||
final = ((uint32_t)pressure)/256.0;
|
||||
|
||||
// Conversion units courtesy of www.endmemo.com.
|
||||
switch(unit){
|
||||
case PresUnit_hPa: /* hPa */
|
||||
final /= 100.0;
|
||||
break;
|
||||
case PresUnit_atm: /* atm */
|
||||
final /= 101324.99766353; /* final pa * 1 atm/101324.99766353Pa */
|
||||
break;
|
||||
case PresUnit_bar: /* bar */
|
||||
final /= 100000.0; /* final pa * 1 bar/100kPa */
|
||||
break;
|
||||
default: /* Pa (case: 0) */
|
||||
break;
|
||||
}
|
||||
return final;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
float BME280::temp(){
|
||||
if(!m_initialized) return 0;
|
||||
int32_t data[8];
|
||||
int32_t t_fine;
|
||||
if(!ReadData(data)){ return NAN; }
|
||||
uint32_t rawTemp = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4);
|
||||
return CalculateTemperature(rawTemp, t_fine);
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
float BME280::pres(PresUnit unit){
|
||||
if(!m_initialized) return 0;
|
||||
int32_t data[8];
|
||||
int32_t t_fine;
|
||||
if(!ReadData(data)){ return NAN; }
|
||||
uint32_t rawTemp = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4);
|
||||
uint32_t rawPressure = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4);
|
||||
CalculateTemperature(rawTemp, t_fine);
|
||||
return CalculatePressure(rawPressure, t_fine);
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
float BME280::hum(){
|
||||
if(!m_initialized) return 0;
|
||||
int32_t data[8];
|
||||
int32_t t_fine;
|
||||
if(!ReadData(data)){ return NAN; }
|
||||
uint32_t rawTemp = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4);
|
||||
uint32_t rawHumidity = (data[6] << 8) | data[7];
|
||||
CalculateTemperature(rawTemp, t_fine);
|
||||
return CalculateHumidity(rawHumidity, t_fine);
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
void BME280::read(float& pressure,float& temp,float& humidity,PresUnit presUnit){
|
||||
if(!m_initialized) return;
|
||||
|
||||
int32_t data[8];
|
||||
int32_t t_fine;
|
||||
if(!ReadData(data)){
|
||||
pressure = temp = humidity = NAN;
|
||||
return;
|
||||
}
|
||||
uint32_t rawPressure = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4);
|
||||
uint32_t rawTemp = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4);
|
||||
uint32_t rawHumidity = (data[6] << 8) | data[7];
|
||||
temp = CalculateTemperature(rawTemp, t_fine);
|
||||
pressure = CalculatePressure(rawPressure, t_fine, presUnit);
|
||||
humidity = CalculateHumidity(rawHumidity, t_fine);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
BME280::ChipModel BME280::chipModel(){
|
||||
return m_chip_model;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool BME280::WriteRegister(uint8_t addr, uint8_t data){
|
||||
i2c->beginTransmission(BME280_ADDRESS);
|
||||
i2c->write(addr);
|
||||
i2c->write(data);
|
||||
i2c->endTransmission();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool BME280::ReadRegister
|
||||
(
|
||||
uint8_t addr,
|
||||
uint8_t data[],
|
||||
uint8_t length
|
||||
)
|
||||
{
|
||||
uint8_t ord(0);
|
||||
|
||||
i2c->beginTransmission(BME280_ADDRESS);
|
||||
i2c->write(addr);
|
||||
i2c->endTransmission();
|
||||
|
||||
i2c->requestFrom(static_cast<uint8_t>(BME280_ADDRESS), length);
|
||||
|
||||
while(i2c->available())
|
||||
{
|
||||
data[ord++] = i2c->read();
|
||||
}
|
||||
|
||||
return ord == length;
|
||||
}
|
124
src/sensor/dev/bme280.h
Normal file
124
src/sensor/dev/bme280.h
Normal file
@ -0,0 +1,124 @@
|
||||
#ifndef TG_BME_280_H
|
||||
#define TG_BME_280_H
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
#define BME280_ADDRESS (0x76)
|
||||
#define BME280_ADDRESS_ALTERNATE (0x77)
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
/// BME280 - Driver class for Bosch Bme280 sensor
|
||||
///
|
||||
/// Based on the data sheet provided by Bosch for
|
||||
/// the Bme280 environmental sensor.
|
||||
///
|
||||
class BME280{
|
||||
public:
|
||||
|
||||
enum PresUnit{
|
||||
PresUnit_Pa,
|
||||
PresUnit_hPa,
|
||||
PresUnit_atm,
|
||||
PresUnit_bar,
|
||||
};
|
||||
|
||||
enum OSR{
|
||||
OSR_Off = 0,
|
||||
OSR_X1 = 1,
|
||||
OSR_X2 = 2,
|
||||
OSR_X4 = 3,
|
||||
OSR_X8 = 4,
|
||||
OSR_X16 = 5
|
||||
};
|
||||
|
||||
enum Mode{
|
||||
Mode_Sleep = 0,
|
||||
Mode_Forced = 1,
|
||||
Mode_Normal = 3
|
||||
};
|
||||
|
||||
enum StandbyTime{
|
||||
StandbyTime_500us = 0,
|
||||
StandbyTime_62500us = 1,
|
||||
StandbyTime_125ms = 2,
|
||||
StandbyTime_250ms = 3,
|
||||
StandbyTime_50ms = 4,
|
||||
StandbyTime_1000ms = 5,
|
||||
StandbyTime_10ms = 6,
|
||||
StandbyTime_20ms = 7
|
||||
};
|
||||
|
||||
enum Filter{
|
||||
Filter_Off = 0,
|
||||
Filter_2 = 1,
|
||||
Filter_4 = 2,
|
||||
Filter_8 = 3,
|
||||
Filter_16 = 4
|
||||
};
|
||||
|
||||
enum ChipModel{
|
||||
ChipModel_UNKNOWN = 0,
|
||||
ChipModel_BMP280 = 0x58,
|
||||
ChipModel_BME280 = 0x60
|
||||
};
|
||||
|
||||
BME280(TwoWire* i2c): m_initialized(false), i2c(i2c){}
|
||||
ChipModel chipModel();
|
||||
|
||||
bool begin();
|
||||
bool reset();
|
||||
|
||||
float temp();
|
||||
float pres(PresUnit unit = PresUnit_hPa);
|
||||
float hum();
|
||||
void read(float& pressure,float& temperature,float& humidity, PresUnit presUnit = PresUnit_hPa);
|
||||
|
||||
protected:
|
||||
bool Initialize();
|
||||
|
||||
private:
|
||||
TwoWire* i2c;
|
||||
uint8_t m_dig[32];
|
||||
ChipModel m_chip_model;
|
||||
bool m_initialized;
|
||||
|
||||
|
||||
static const uint8_t CTRL_HUM_ADDR = 0xF2;
|
||||
static const uint8_t CTRL_MEAS_ADDR = 0xF4;
|
||||
static const uint8_t CONFIG_ADDR = 0xF5;
|
||||
static const uint8_t PRESS_ADDR = 0xF7;
|
||||
static const uint8_t TEMP_ADDR = 0xFA;
|
||||
static const uint8_t HUM_ADDR = 0xFD;
|
||||
static const uint8_t TEMP_DIG_ADDR = 0x88;
|
||||
static const uint8_t PRESS_DIG_ADDR = 0x8E;
|
||||
static const uint8_t HUM_DIG_ADDR1 = 0xA1;
|
||||
static const uint8_t HUM_DIG_ADDR2 = 0xE1;
|
||||
static const uint8_t ID_ADDR = 0xD0;
|
||||
static const uint8_t RESET_ADDR = 0xE0;
|
||||
|
||||
static const uint8_t RESET_VALUE = 0xB6;
|
||||
|
||||
static const uint8_t TEMP_DIG_LENGTH = 6;
|
||||
static const uint8_t PRESS_DIG_LENGTH = 18;
|
||||
static const uint8_t HUM_DIG_ADDR1_LENGTH = 1;
|
||||
static const uint8_t HUM_DIG_ADDR2_LENGTH = 7;
|
||||
static const uint8_t DIG_LENGTH = 32;
|
||||
static const uint8_t SENSOR_DATA_LENGTH = 8;
|
||||
|
||||
|
||||
void WriteSettings();
|
||||
bool ReadChipID();
|
||||
bool ReadTrim();
|
||||
|
||||
bool ReadData(int32_t data[8]);
|
||||
|
||||
bool WriteRegister(uint8_t addr,uint8_t data);
|
||||
bool ReadRegister(uint8_t addr,uint8_t data[],uint8_t length);
|
||||
|
||||
float CalculateTemperature(int32_t raw,int32_t& t_fine);
|
||||
float CalculateHumidity(int32_t raw,int32_t t_fine);
|
||||
float CalculatePressure(int32_t raw,int32_t t_fine,PresUnit unit = PresUnit_hPa);
|
||||
};
|
||||
|
||||
#endif // TG_BME_280_H
|
0
src/sensor/dev/icm20948.h
Normal file
0
src/sensor/dev/icm20948.h
Normal file
137
src/sensor/dev/ltr390.cpp
Normal file
137
src/sensor/dev/ltr390.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
#include "ltr390.h"
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool LTR390::Initialize(){
|
||||
bool success(true);
|
||||
|
||||
success &= ReadChipID();
|
||||
|
||||
if(success){
|
||||
WriteSettings();
|
||||
}
|
||||
m_initialized = success;
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool LTR390::ReadChipID(){
|
||||
uint8_t id;
|
||||
|
||||
ReadRegister(ID_ADDR, &id, 1);
|
||||
|
||||
switch(id){
|
||||
case ChipModel_LTR390_REV0:
|
||||
m_chip_model = ChipModel_LTR390_REV0;
|
||||
break;
|
||||
case ChipModel_LTR390_REV1:
|
||||
m_chip_model = ChipModel_LTR390_REV1;
|
||||
break;
|
||||
case ChipModel_LTR390_REV2:
|
||||
m_chip_model = ChipModel_LTR390_REV2;
|
||||
break;
|
||||
case ChipModel_LTR390_REV3:
|
||||
m_chip_model = ChipModel_LTR390_REV3;
|
||||
break;
|
||||
default:
|
||||
m_chip_model = ChipModel_UNKNOWN;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
void LTR390::WriteSettings(){
|
||||
uint8_t ctrlMeas = LTR390_RESOLUTION_16BIT | LTR390_RATE_1000;
|
||||
uint8_t ctrlGain = LTR390_GAIN_3;
|
||||
uint8_t ctrlMode = LTR390_ON | LTR390_MODE_UVS;
|
||||
|
||||
WriteRegister(MEAS_RATE, ctrlMeas);
|
||||
WriteRegister(GAIN, ctrlGain);
|
||||
WriteRegister(MAIN_CTRL, ctrlMode);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool LTR390::begin(){
|
||||
bool success = Initialize();
|
||||
success &= m_initialized;
|
||||
return success;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
bool LTR390::reset(){
|
||||
WriteRegister(RESET_ADDR, RESET_VALUE);
|
||||
delay(10); //max. startup time according to datasheet
|
||||
return(begin());
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
bool LTR390::ReadData(int32_t data[SENSOR_DATA_LENGTH], uint32_t addr){
|
||||
bool success;
|
||||
uint8_t buffer[SENSOR_DATA_LENGTH];
|
||||
|
||||
// WriteSettings();
|
||||
|
||||
success = ReadRegister(addr, buffer, SENSOR_DATA_LENGTH);
|
||||
|
||||
for(int i = 0; i < SENSOR_DATA_LENGTH; ++i){
|
||||
data[i] = static_cast<int32_t>(buffer[i]);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
uint32_t LTR390::uv(){
|
||||
if(!m_initialized) return 0;
|
||||
int32_t data[SENSOR_DATA_LENGTH];
|
||||
if(!ReadData(data, UVSDATA)){ return 0; }
|
||||
uint32_t rawUV = (data[2] << 16) | (data[1] << 8) | (data[0]);
|
||||
return rawUV;
|
||||
}
|
||||
|
||||
void LTR390::read(uint32_t& uvs, uint32_t& uvi){
|
||||
if(!m_initialized) return;
|
||||
uvs = uv();
|
||||
uvi = (uvs/ (3*0.25))*3;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
LTR390::ChipModel LTR390::chipModel(){
|
||||
return m_chip_model;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool LTR390::WriteRegister(uint8_t addr, uint8_t data){
|
||||
i2c->beginTransmission(LTR390_ADDRESS);
|
||||
i2c->write(addr);
|
||||
i2c->write(data);
|
||||
i2c->endTransmission();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool LTR390::ReadRegister(uint8_t addr,uint8_t data[],uint8_t length){
|
||||
uint8_t ord(0);
|
||||
|
||||
i2c->beginTransmission(LTR390_ADDRESS);
|
||||
i2c->write(addr);
|
||||
i2c->endTransmission();
|
||||
|
||||
i2c->requestFrom(static_cast<uint8_t>(LTR390_ADDRESS), length);
|
||||
|
||||
while(i2c->available()){
|
||||
data[ord++] = i2c->read();
|
||||
}
|
||||
|
||||
return ord == length;
|
||||
}
|
110
src/sensor/dev/ltr390.h
Normal file
110
src/sensor/dev/ltr390.h
Normal file
@ -0,0 +1,110 @@
|
||||
#ifndef TG_LTR_390_H
|
||||
#define TG_LTR_390_H
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
#define LTR390_ADDRESS (0x53)
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
/// LTR390 - Driver class for Ltr390 sensor
|
||||
///
|
||||
/// Based on the data sheet provided
|
||||
///
|
||||
class LTR390{
|
||||
public:
|
||||
|
||||
typedef enum {
|
||||
LTR390_ON = 0x2,
|
||||
LTR390_MODE_ALS = 0x0,
|
||||
LTR390_MODE_UVS = 0x8,
|
||||
} ltr390_mode_t;
|
||||
|
||||
/*! @brief Sensor gain for UV or ALS */
|
||||
typedef enum {
|
||||
LTR390_GAIN_1 = 0,
|
||||
LTR390_GAIN_3 = 1,
|
||||
LTR390_GAIN_6 = 2,
|
||||
LTR390_GAIN_9 = 3,
|
||||
LTR390_GAIN_18 = 4,
|
||||
} ltr390_gain_t;
|
||||
|
||||
/*! @brief Measurement resolution (higher res means slower reads!) */
|
||||
typedef enum {
|
||||
LTR390_RESOLUTION_20BIT = 0x0,
|
||||
LTR390_RESOLUTION_19BIT = 0x10,
|
||||
LTR390_RESOLUTION_18BIT = 0x20,
|
||||
LTR390_RESOLUTION_17BIT = 0x30,
|
||||
LTR390_RESOLUTION_16BIT = 0x40,
|
||||
LTR390_RESOLUTION_13BIT = 0x50,
|
||||
} ltr390_resolution_t;
|
||||
|
||||
|
||||
/*! @brief Measurement resolution (higher res means slower reads!) */
|
||||
typedef enum {
|
||||
LTR390_RATE_25 = 0x0,
|
||||
LTR390_RATE_50 = 0x1,
|
||||
LTR390_RATE_100 = 0x2,
|
||||
LTR390_RATE_200 = 0x3,
|
||||
LTR390_RATE_500 = 0x4,
|
||||
LTR390_RATE_1000 = 0x5,
|
||||
LTR390_RATE_2000 = 0x6,
|
||||
} ltr390_rate_t;
|
||||
|
||||
enum ChipModel{
|
||||
ChipModel_UNKNOWN = 0,
|
||||
ChipModel_LTR390_REV0 = 0xB0,
|
||||
ChipModel_LTR390_REV1 = 0xB1,
|
||||
ChipModel_LTR390_REV2 = 0xB2,
|
||||
ChipModel_LTR390_REV3 = 0xB3,
|
||||
};
|
||||
|
||||
LTR390(TwoWire* i2c): m_initialized(false),i2c(i2c){}
|
||||
|
||||
ChipModel chipModel();
|
||||
|
||||
bool begin();
|
||||
bool reset();
|
||||
|
||||
uint32_t uv();
|
||||
void read(uint32_t& uv, uint32_t& uvi);
|
||||
|
||||
|
||||
protected:
|
||||
bool Initialize();
|
||||
void InitializeFilter();
|
||||
|
||||
|
||||
private:
|
||||
TwoWire* i2c;
|
||||
ChipModel m_chip_model;
|
||||
bool m_initialized;
|
||||
|
||||
static const uint8_t MAIN_CTRL = 0x00; ///< Main control register
|
||||
static const uint8_t MEAS_RATE = 0x04; ///< Resolution and data rate
|
||||
static const uint8_t GAIN = 0x05; ///< ALS and UVS gain range
|
||||
static const uint8_t ID_ADDR = 0x06; ///< Part id/revision register
|
||||
static const uint8_t MAIN_STATUS = 0x07; ///< Main status register
|
||||
static const uint8_t ALSDATA = 0x0D; ///< ALS data lowest byte
|
||||
static const uint8_t UVSDATA = 0x10; ///< UVS data lowest byte
|
||||
static const uint8_t INT_CFG = 0x19; ///< Interrupt configuration
|
||||
static const uint8_t INT_PST = 0x1A; ///< Interrupt persistance config
|
||||
static const uint8_t THRESH_UP = 0x21; ///< Upper threshold, low byte
|
||||
static const uint8_t THRESH_LOW = 0x24; ///< Lower threshold, low byte
|
||||
|
||||
static const uint8_t RESET_ADDR = 0x00; ///< Reset Address
|
||||
static const uint8_t RESET_VALUE = 0x10; ///< Reset value
|
||||
|
||||
static const uint8_t SENSOR_DATA_LENGTH = 3; //For 16 bit resolution !
|
||||
|
||||
bool ReadChipID();
|
||||
bool ReadTrim();
|
||||
|
||||
bool ReadData(int32_t data[SENSOR_DATA_LENGTH], uint32_t addr);
|
||||
bool ReadRegister(uint8_t addr,uint8_t data[],uint8_t length);
|
||||
|
||||
void WriteSettings();
|
||||
bool WriteRegister(uint8_t addr,uint8_t data);
|
||||
};
|
||||
|
||||
#endif
|
131
src/sensor/dev/pmsa003.cpp
Normal file
131
src/sensor/dev/pmsa003.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
#include "pmsa003.h"
|
||||
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
/****************************************************************/
|
||||
bool PMSA003::Initialize(){
|
||||
bool success(true);
|
||||
|
||||
success &= ReadChipID();
|
||||
|
||||
if(success) success = WriteSettings();
|
||||
|
||||
m_initialized = success;
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool PMSA003::ReadChipID(){
|
||||
uint8_t id = 0;
|
||||
|
||||
ReadRegister(REG_VERSION, &id, 1);
|
||||
Serial.print("PMSSA DEV: ");Serial.println(id);
|
||||
// switch(id){
|
||||
// case ChipModel_PMSA003_REV0:
|
||||
// m_chip_model = ChipModel_PMSA003_REV0;
|
||||
// break;
|
||||
// default:
|
||||
// m_chip_model = ChipModel_UNKNOWN;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool PMSA003::WriteSettings(){
|
||||
return true; //No settings
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool PMSA003::begin(){
|
||||
bool success = Initialize();
|
||||
success &= m_initialized;
|
||||
return success;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
bool PMSA003::reset(){
|
||||
return true; //Cannot be reset
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
bool PMSA003::ReadData(uint8_t data[SENSOR_DATA_LENGTH]){
|
||||
|
||||
ReadRegister(REG_Char1,data,SENSOR_DATA_LENGTH);
|
||||
|
||||
if (data[0] != 0x42 || data[1] != 0x4d) return false;
|
||||
|
||||
uint16_t sum = 0;
|
||||
for (uint8_t i = 0; i < 30; i++) sum += data[i];
|
||||
uint16_t checksum = data[30]<<8 | data[31];
|
||||
if (sum != checksum) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
void PMSA003::read(PM25_AQI_Data& data){
|
||||
if(!m_initialized) return;
|
||||
uint8_t rd[SENSOR_DATA_LENGTH];
|
||||
if(!ReadData(rd)) return;
|
||||
uint16_t md[16] = {0};
|
||||
for (uint8_t i = 0; i < 15; i++) {
|
||||
md[i] = rd[i * 2] << 8;
|
||||
md[i] |= rd[i * 2 + 1];
|
||||
}
|
||||
|
||||
data.pm10_standard = md[2];
|
||||
data.pm25_standard = md[3];
|
||||
data.pm100_standard = md[4];
|
||||
data.pm10_env = md[5];
|
||||
data.pm25_env = md[6];
|
||||
data.pm100_env = md[7];
|
||||
data.particles_03um = md[8];
|
||||
data.particles_05um = md[9];
|
||||
data.particles_10um = md[10];
|
||||
data.particles_25um = md[11];
|
||||
data.particles_50um = md[12];
|
||||
data.particles_100um = md[13];
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
PMSA003::ChipModel PMSA003::chipModel(){
|
||||
return m_chip_model;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool PMSA003::WriteRegister(uint16_t addr, uint8_t data){
|
||||
i2c->beginTransmission(PMSA003_ADDRESS);
|
||||
i2c->write(highByte(addr));
|
||||
i2c->write(lowByte(addr));
|
||||
i2c->write(data);
|
||||
i2c->endTransmission();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool PMSA003::ReadRegister(uint8_t addr,uint8_t data[],uint8_t length){
|
||||
uint8_t ord(0);
|
||||
|
||||
i2c->beginTransmission(PMSA003_ADDRESS);
|
||||
i2c->write(addr);
|
||||
i2c->endTransmission();
|
||||
|
||||
i2c->requestFrom(static_cast<uint8_t>(PMSA003_ADDRESS), length);
|
||||
|
||||
while(i2c->available()){
|
||||
data[ord++] = i2c->read();
|
||||
}
|
||||
|
||||
return ord == length;
|
||||
}
|
106
src/sensor/dev/pmsa003.h
Normal file
106
src/sensor/dev/pmsa003.h
Normal file
@ -0,0 +1,106 @@
|
||||
#ifndef TG_PMSA003_H
|
||||
#define TG_PMSA003_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
|
||||
#define PMSA003_ADDRESS (0x12)
|
||||
|
||||
#define SENSOR_DATA_LENGTH 32
|
||||
|
||||
typedef struct PMSAQIdata {
|
||||
uint16_t pm10_standard, ///< Standard PM1.0
|
||||
pm25_standard, ///< Standard PM2.5
|
||||
pm100_standard; ///< Standard PM10.0
|
||||
uint16_t pm10_env, ///< Environmental PM1.0
|
||||
pm25_env, ///< Environmental PM2.5
|
||||
pm100_env; ///< Environmental PM10.0
|
||||
uint16_t particles_03um, ///< 0.3um Particle Count
|
||||
particles_05um, ///< 0.5um Particle Count
|
||||
particles_10um, ///< 1.0um Particle Count
|
||||
particles_25um, ///< 2.5um Particle Count
|
||||
particles_50um, ///< 5.0um Particle Count
|
||||
particles_100um; ///< 10.0um Particle Count
|
||||
} PM25_AQI_Data;
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
/// PMSA003 - Driver class for PMSA003 sensor
|
||||
///
|
||||
/// Based on the data sheet provided
|
||||
///
|
||||
class PMSA003{
|
||||
public:
|
||||
|
||||
enum ChipModel{
|
||||
ChipModel_UNKNOWN = 0,
|
||||
ChipModel_PMSA003_REV0 = 0x10
|
||||
};
|
||||
|
||||
|
||||
PMSA003(TwoWire* i2c): m_initialized(false),i2c(i2c){}
|
||||
|
||||
ChipModel chipModel();
|
||||
|
||||
bool begin();
|
||||
bool reset();
|
||||
|
||||
void read(PM25_AQI_Data& data);
|
||||
|
||||
|
||||
protected:
|
||||
bool Initialize();
|
||||
|
||||
|
||||
private:
|
||||
bool m_initialized;
|
||||
ChipModel m_chip_model;
|
||||
TwoWire* i2c;
|
||||
|
||||
static const uint8_t REG_Char1 = 0x00; // 0x42
|
||||
static const uint8_t REG_Char2 = 0x01; // 0x4d
|
||||
static const uint8_t REG_FrameH = 0x02; // Frame length = 2x13 + 2
|
||||
static const uint8_t REG_FrameL = 0x03; // --
|
||||
static const uint8_t REG_d1h = 0x04; // PM1.0 ug/m3 (standard)
|
||||
static const uint8_t REG_d1l = 0x05;
|
||||
static const uint8_t REG_d2h = 0x06; // PM2.5 ug/m3 (standard)
|
||||
static const uint8_t REG_d2l = 0x07;
|
||||
static const uint8_t REG_d3h = 0x08; // PM10 ug/m3 (standard)
|
||||
static const uint8_t REG_d3l = 0x09;
|
||||
static const uint8_t REG_d4h = 0x0A; // PM1.0 ug/m3 (atmospheric env)
|
||||
static const uint8_t REG_d4l = 0x0B;
|
||||
static const uint8_t REG_d5h = 0x0C; // PM2.5 ug/m3 (atmospheric env)
|
||||
static const uint8_t REG_d5l = 0x0D;
|
||||
static const uint8_t REG_d6h = 0x0E; // PM10 ug/m3 (atmospheric env)
|
||||
static const uint8_t REG_d6l = 0x0F;
|
||||
static const uint8_t REG_d7h = 0x10; // >0.3um/0.1L
|
||||
static const uint8_t REG_d7l = 0x11;
|
||||
static const uint8_t REG_d8h = 0x12; // >0.5um/0.1L
|
||||
static const uint8_t REG_d8l = 0x13;
|
||||
static const uint8_t REG_d9h = 0x14; // >1.0um/0.1L
|
||||
static const uint8_t REG_d9l = 0x15;
|
||||
static const uint8_t REG_d10h = 0x16; // >2.5um/0.1L
|
||||
static const uint8_t REG_d10l = 0x17;
|
||||
static const uint8_t REG_d11h = 0x18; // >5.0um/0.1L
|
||||
static const uint8_t REG_d11l = 0x19;
|
||||
static const uint8_t REG_d12h = 0x1A; // >10.0um/0.1L
|
||||
static const uint8_t REG_d12l = 0x1B;
|
||||
|
||||
static const uint8_t REG_VERSION = 0x1C; // Verion
|
||||
static const uint8_t REG_ERR = 0x1D; // Error
|
||||
|
||||
static const uint8_t REG_checkh = 0x1E; // Checksum
|
||||
static const uint8_t REG_checkl = 0x1D;
|
||||
|
||||
bool ReadChipID();
|
||||
|
||||
bool ReadRegister(uint8_t addr,uint8_t data[],uint8_t length);
|
||||
bool ReadData(uint8_t data[SENSOR_DATA_LENGTH]);
|
||||
|
||||
bool WriteSettings();
|
||||
bool WriteRegister(uint16_t addr,uint8_t data);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
180
src/sensor/dev/sgp40.cpp
Normal file
180
src/sensor/dev/sgp40.cpp
Normal file
@ -0,0 +1,180 @@
|
||||
#include "sgp40.h"
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool SGP40::Initialize(){
|
||||
bool success(true);
|
||||
|
||||
success &= ReadChipID();
|
||||
|
||||
VocAlgorithm_init(&vocAlgorithmParameters);
|
||||
|
||||
if(success) success = WriteSettings();
|
||||
|
||||
m_initialized = success;
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool SGP40::ReadChipID(){
|
||||
uint8_t id = 0;
|
||||
|
||||
//ReadRegister(ID_ADDR, &id, 1);
|
||||
|
||||
switch(id){
|
||||
default:
|
||||
m_chip_model = ChipModel_UNKNOWN;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool SGP40::WriteSettings(){
|
||||
uint8_t data[3];
|
||||
uint8_t ord(0);
|
||||
|
||||
i2c->beginTransmission(SGP40_ADDRESS);
|
||||
i2c->write(highByte(REG_MEASURE_TEST));
|
||||
i2c->write(lowByte(REG_MEASURE_TEST));
|
||||
i2c->endTransmission();
|
||||
|
||||
delay(320);
|
||||
|
||||
i2c->requestFrom(static_cast<uint8_t>(SGP40_ADDRESS), uint8_t(3));
|
||||
|
||||
while(i2c->available()){
|
||||
data[ord++] = i2c->read();
|
||||
}
|
||||
if(ord != 3) return false;
|
||||
uint16_t results = (data[0] << 8) | data[1];
|
||||
|
||||
return (results == test_pass);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool SGP40::begin(){
|
||||
bool success = Initialize();
|
||||
success &= m_initialized;
|
||||
return success;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
bool SGP40::reset(){
|
||||
WriteRegister(RESET_ADDR, 0x02);
|
||||
delay(10); //max. startup time according to datasheet
|
||||
return(begin());
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
bool SGP40::ReadData(uint8_t data[SENSOR_DATA_LENGTH], float RH, float T){
|
||||
bool success;
|
||||
uint8_t ord(0);
|
||||
|
||||
RH = (RH>100?100: (RH<0?0:RH));
|
||||
T = (T>130?130: (T<-45?-45:T));
|
||||
|
||||
uint16_t RH_ticks = (uint16_t)(RH * 65535 / 100); // Convert RH from %RH to ticks
|
||||
uint16_t T_ticks = (uint16_t)((T + 45) * 65535 / 175); // Convert T from DegC to ticks
|
||||
|
||||
i2c->beginTransmission(SGP40_ADDRESS);
|
||||
i2c->write(highByte(REG_MEASURE_RAW));
|
||||
i2c->write(lowByte(REG_MEASURE_RAW));
|
||||
|
||||
i2c->write(highByte(RH_ticks));
|
||||
i2c->write(lowByte(RH_ticks));
|
||||
i2c->write(CRC8(RH_ticks));
|
||||
|
||||
i2c->write(highByte(T_ticks));
|
||||
i2c->write(lowByte(T_ticks));
|
||||
i2c->write(CRC8(T_ticks));
|
||||
|
||||
i2c->endTransmission();
|
||||
|
||||
delay(30);
|
||||
|
||||
i2c->requestFrom(SGP40_ADDRESS, SENSOR_DATA_LENGTH);
|
||||
|
||||
while(i2c->available()){
|
||||
data[ord++] = i2c->read();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
int32_t SGP40::voc(float RH, float T){
|
||||
if(!m_initialized) return 0;
|
||||
uint8_t data[SENSOR_DATA_LENGTH];
|
||||
ReadData(data, RH, T);
|
||||
uint16_t results = (data[0]<<8) | data[1];
|
||||
int32_t voci = 0;
|
||||
VocAlgorithm_process(&vocAlgorithmParameters, results, &voci);
|
||||
|
||||
return voci;
|
||||
|
||||
}
|
||||
void SGP40::read(int32_t& voc, float RH, float T){
|
||||
if(!m_initialized) return;
|
||||
uint8_t data[SENSOR_DATA_LENGTH];
|
||||
ReadData(data, RH, T);
|
||||
uint16_t results = (data[0]<<8) | data[1];
|
||||
VocAlgorithm_process(&vocAlgorithmParameters, results, &voc);
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
SGP40::ChipModel SGP40::chipModel(){
|
||||
return m_chip_model;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool SGP40::WriteRegister(uint16_t addr, uint8_t data){
|
||||
i2c->beginTransmission(SGP40_ADDRESS);
|
||||
i2c->write(highByte(addr));
|
||||
i2c->write(lowByte(addr));
|
||||
i2c->write(data);
|
||||
i2c->endTransmission();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool SGP40::ReadRegister(uint8_t addr,uint8_t data[],uint8_t length){
|
||||
uint8_t ord(0);
|
||||
|
||||
i2c->beginTransmission(SGP40_ADDRESS);
|
||||
i2c->write(addr);
|
||||
i2c->endTransmission();
|
||||
|
||||
i2c->requestFrom(static_cast<uint8_t>(SGP40_ADDRESS), length);
|
||||
|
||||
while(i2c->available()){
|
||||
data[ord++] = i2c->read();
|
||||
}
|
||||
|
||||
return ord == length;
|
||||
}
|
||||
|
||||
|
||||
uint8_t SGP40::CRC8(uint16_t data){
|
||||
uint8_t crc = 0xFF;
|
||||
crc ^= (data >> 8);
|
||||
for (uint8_t i = 0 ; i < 8 ; i++){
|
||||
if ((crc & 0x80) != 0) crc = (uint8_t)((crc << 1) ^ 0x31);
|
||||
else crc <<= 1;
|
||||
}
|
||||
crc ^= (uint8_t)data;
|
||||
for (uint8_t i = 0 ; i < 8 ; i++){
|
||||
if ((crc & 0x80) != 0) crc = (uint8_t)((crc << 1) ^ 0x31);
|
||||
else crc <<= 1;
|
||||
}
|
||||
return crc;
|
||||
}
|
67
src/sensor/dev/sgp40.h
Normal file
67
src/sensor/dev/sgp40.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef TG_SGP40_H
|
||||
#define TG_SGP40_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include "../voc.h"
|
||||
|
||||
|
||||
#define SGP40_ADDRESS (0x59)
|
||||
|
||||
#define SENSOR_DATA_LENGTH 3
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
/// SGP40 - Driver class for SGP40 sensor
|
||||
///
|
||||
/// Based on the data sheet provided
|
||||
///
|
||||
class SGP40{
|
||||
public:
|
||||
|
||||
enum ChipModel{
|
||||
ChipModel_UNKNOWN = 0
|
||||
};
|
||||
|
||||
|
||||
SGP40(TwoWire* i2c): m_initialized(false),i2c(i2c){}
|
||||
|
||||
ChipModel chipModel();
|
||||
|
||||
bool begin();
|
||||
bool reset();
|
||||
|
||||
int32_t voc(float RH = 50, float T = 20);
|
||||
void read(int32_t& voc, float RH = 50, float T = 20);
|
||||
|
||||
|
||||
protected:
|
||||
bool Initialize();
|
||||
|
||||
|
||||
private:
|
||||
bool m_initialized;
|
||||
ChipModel m_chip_model;
|
||||
TwoWire* i2c;
|
||||
VocAlgorithmParams vocAlgorithmParameters;
|
||||
|
||||
static const uint16_t REG_MEASURE_RAW = 0x260F;
|
||||
static const uint16_t REG_MEASURE_TEST = 0x280E;
|
||||
static const uint16_t REG_HEATER_OFF = 0x3615;
|
||||
static const uint16_t RESET_ADDR = 0x0006;
|
||||
|
||||
static const uint16_t test_pass = 0xD400;
|
||||
static const uint16_t test_fail = 0x4B00;
|
||||
|
||||
bool ReadChipID();
|
||||
|
||||
bool ReadRegister(uint8_t addr,uint8_t data[],uint8_t length);
|
||||
bool ReadData(uint8_t data[SENSOR_DATA_LENGTH], float RH, float T);
|
||||
|
||||
bool WriteSettings();
|
||||
bool WriteRegister(uint16_t addr,uint8_t data);
|
||||
|
||||
uint8_t CRC8(uint16_t twoBytes);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
228
src/sensor/dev/tsl25911.cpp
Normal file
228
src/sensor/dev/tsl25911.cpp
Normal file
@ -0,0 +1,228 @@
|
||||
#include "tsl25911.h"
|
||||
|
||||
|
||||
|
||||
#define ENABLE_POWEROFF (0x00) ///< Flag for ENABLE register to disable
|
||||
#define ENABLE_POWERON (0x01) ///< Flag for ENABLE register to enable
|
||||
#define ENABLE_AEN (0x02) ///< ALS Enable. This field activates ALS function. Writing a one
|
||||
///< activates the ALS. Writing a zero disables the ALS.
|
||||
#define ENABLE_AIEN (0x10) ///< ALS Interrupt Enable. When asserted permits ALS interrupts to be
|
||||
///< generated, subject to the persist filter.
|
||||
#define ENABLE_NPIEN (0x80) ///< No Persist Interrupt Enable. When asserted NP Threshold conditions
|
||||
///< will generate an interrupt, bypassing the persist filter
|
||||
|
||||
#define LUX_DF (408.0F) ///< Lux cooefficient
|
||||
#define LUX_COEFB (1.64F) ///< CH0 coefficient
|
||||
#define LUX_COEFC (0.59F) ///< CH1 coefficient A
|
||||
#define LUX_COEFD (0.86F) ///< CH2 coefficient B
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool TSL25911::Initialize(){
|
||||
bool success(true);
|
||||
|
||||
success &= ReadChipID();
|
||||
|
||||
if(success) WriteSettings();
|
||||
|
||||
m_initialized = success;
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool TSL25911::ReadChipID(){
|
||||
uint8_t id;
|
||||
ReadRegister(ID_ADDR, &id, 1);
|
||||
switch(id){
|
||||
case ChipModel_TSL25911_REV0:
|
||||
m_chip_model = ChipModel_TSL25911_REV0;
|
||||
default:
|
||||
m_chip_model = ChipModel_UNKNOWN;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
void TSL25911::WriteSettings(){
|
||||
WriteRegister(REG_ENABLE, ENABLE_POWERON | ENABLE_AEN);
|
||||
|
||||
WriteRegister(REG_CTRL, integration | gain);
|
||||
|
||||
WriteRegister(REG_ENABLE,ENABLE_POWEROFF);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool TSL25911::begin(){
|
||||
bool success = Initialize();
|
||||
success &= m_initialized;
|
||||
return success;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
bool TSL25911::reset(){
|
||||
//Write RST REG ?
|
||||
delay(10); //max. startup time according to datasheet
|
||||
return(begin());
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
bool TSL25911::ReadData(uint32_t data[SENSOR_DATA_LENGTH]){
|
||||
bool success;
|
||||
success &= WriteRegister(REG_ENABLE, ENABLE_POWERON | ENABLE_AEN);
|
||||
|
||||
|
||||
for (uint8_t d = 0; d <= integration; d++) // Wait x ms for ADC to complete
|
||||
delay(120);
|
||||
|
||||
success &= ReadRegister(CHAN0_LOW,static_cast<uint8_t*>(static_cast<void*>(&data[0])),2);
|
||||
success &= ReadRegister(CHAN1_LOW,static_cast<uint8_t*>(static_cast<void*>(&data[2])),2);
|
||||
|
||||
success &= WriteRegister(REG_ENABLE,ENABLE_POWEROFF);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
float ComputeLux(uint16_t ch0, uint16_t ch1, float atime, float again) {
|
||||
float cpl, lux1, lux2, lux;
|
||||
|
||||
if ((ch0 == 0xFFFF) | (ch1 == 0xFFFF)) return -1;
|
||||
|
||||
cpl = (atime * again) / LUX_DF;
|
||||
lux = (((float)ch0 - (float)ch1)) * (1.0F - ((float)ch1 / (float)ch0)) / cpl;
|
||||
return lux;
|
||||
}
|
||||
|
||||
uint16_t TSL25911::lumV(){
|
||||
|
||||
if(!m_initialized) return 0;
|
||||
uint32_t data;
|
||||
if(ReadData(&data))
|
||||
return ((data & 0xFFFF) - (data >> 16));
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t TSL25911::lumIR(){
|
||||
if(!m_initialized) return 0;
|
||||
uint32_t data;
|
||||
if(ReadData(&data))
|
||||
return (data >> 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t TSL25911::lumF(){
|
||||
if(!m_initialized) return 0;
|
||||
uint32_t data;
|
||||
if(ReadData(&data))
|
||||
return (data & 0xFFFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float TSL25911::lumLux(){
|
||||
if(!m_initialized) return 0;
|
||||
uint32_t data;
|
||||
if(ReadData(&data)){
|
||||
return ComputeLux(data&0xFFFF, data>>16,again(),atime());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TSL25911::read(uint16_t& v, uint16_t& ir, uint16_t& f, float& lux){
|
||||
if(!m_initialized) return;
|
||||
uint32_t data;
|
||||
if(ReadData(&data)){
|
||||
v = ((data & 0xFFFF) - (data >> 16));
|
||||
ir = (data >> 16);
|
||||
f = (data & 0xFFFF);
|
||||
lux = ComputeLux(data&0xFFFF,data>>16,again(),atime());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
TSL25911::ChipModel TSL25911::chipModel(){
|
||||
return m_chip_model;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool TSL25911::WriteRegister(uint8_t addr, uint8_t data){
|
||||
i2c->beginTransmission(TSL25911_ADDRESS);
|
||||
i2c->write(addr);
|
||||
i2c->write(data);
|
||||
i2c->endTransmission();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
bool TSL25911::ReadRegister(uint8_t addr,uint8_t data[],uint8_t length){
|
||||
uint8_t ord(0);
|
||||
|
||||
i2c->beginTransmission(TSL25911_ADDRESS);
|
||||
i2c->write(addr);
|
||||
i2c->endTransmission();
|
||||
|
||||
i2c->requestFrom(static_cast<uint8_t>(TSL25911_ADDRESS), length);
|
||||
|
||||
while(i2c->available()){
|
||||
data[ord++] = i2c->read();
|
||||
}
|
||||
|
||||
return ord == length;
|
||||
}
|
||||
|
||||
float TSL25911::again(){
|
||||
switch (gain) {
|
||||
case TSL2591_GAIN_LOW:
|
||||
return 1.0F;
|
||||
break;
|
||||
case TSL2591_GAIN_MED:
|
||||
return 25.0F;
|
||||
break;
|
||||
case TSL2591_GAIN_HIGH:
|
||||
return 428.0F;
|
||||
break;
|
||||
case TSL2591_GAIN_MAX:
|
||||
return 9876.0F;
|
||||
break;
|
||||
default:
|
||||
return 1.0F;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float TSL25911::atime(){
|
||||
switch (integration) {
|
||||
case TSL2591_INTEGRATIONTIME_100MS:
|
||||
return 100.0F;
|
||||
break;
|
||||
case TSL2591_INTEGRATIONTIME_200MS:
|
||||
return 200.0F;
|
||||
break;
|
||||
case TSL2591_INTEGRATIONTIME_300MS:
|
||||
return 300.0F;
|
||||
break;
|
||||
case TSL2591_INTEGRATIONTIME_400MS:
|
||||
return 400.0F;
|
||||
break;
|
||||
case TSL2591_INTEGRATIONTIME_500MS:
|
||||
return 500.0F;
|
||||
break;
|
||||
case TSL2591_INTEGRATIONTIME_600MS:
|
||||
return 600.0F;
|
||||
break;
|
||||
default: // 100ms
|
||||
return 100.0F;
|
||||
break;
|
||||
}
|
||||
}
|
121
src/sensor/dev/tsl25911.h
Normal file
121
src/sensor/dev/tsl25911.h
Normal file
@ -0,0 +1,121 @@
|
||||
#ifndef TG_TSL25911_H
|
||||
#define TG_TSL25911_H
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
|
||||
#define TSL25911_ADDRESS (0x29)
|
||||
|
||||
#define SENSOR_DATA_LENGTH 4
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
/// TSL25911 - Driver class for TSL25911 sensor
|
||||
///
|
||||
/// Based on the data sheet provided
|
||||
///
|
||||
class TSL25911{
|
||||
public:
|
||||
|
||||
typedef enum {
|
||||
TSL25911_FULL = 0x0,
|
||||
TSL25911_IR = 0x1,
|
||||
TSL25911_VIS = 0x2,
|
||||
} tls25911_mode_t;
|
||||
|
||||
typedef enum {
|
||||
TSL2591_INTEGRATIONTIME_100MS = 0x00, // 100 millis
|
||||
TSL2591_INTEGRATIONTIME_200MS = 0x01, // 200 millis
|
||||
TSL2591_INTEGRATIONTIME_300MS = 0x02, // 300 millis
|
||||
TSL2591_INTEGRATIONTIME_400MS = 0x03, // 400 millis
|
||||
TSL2591_INTEGRATIONTIME_500MS = 0x04, // 500 millis
|
||||
TSL2591_INTEGRATIONTIME_600MS = 0x05, // 600 millis
|
||||
} tsl2591IntegrationTime_t;
|
||||
|
||||
/// Enumeration for the persistance filter (for interrupts)
|
||||
typedef enum {// bit 7:4: 0
|
||||
TSL2591_PERSIST_EVERY = 0x00, // Every ALS cycle generates an interrupt
|
||||
TSL2591_PERSIST_ANY = 0x01, // Any value outside of threshold range
|
||||
TSL2591_PERSIST_2 = 0x02, // 2 consecutive values out of range
|
||||
TSL2591_PERSIST_3 = 0x03, // 3 consecutive values out of range
|
||||
TSL2591_PERSIST_5 = 0x04, // 5 consecutive values out of range
|
||||
TSL2591_PERSIST_10 = 0x05, // 10 consecutive values out of range
|
||||
TSL2591_PERSIST_15 = 0x06, // 15 consecutive values out of range
|
||||
TSL2591_PERSIST_20 = 0x07, // 20 consecutive values out of range
|
||||
TSL2591_PERSIST_25 = 0x08, // 25 consecutive values out of range
|
||||
TSL2591_PERSIST_30 = 0x09, // 30 consecutive values out of range
|
||||
TSL2591_PERSIST_35 = 0x0A, // 35 consecutive values out of range
|
||||
TSL2591_PERSIST_40 = 0x0B, // 40 consecutive values out of range
|
||||
TSL2591_PERSIST_45 = 0x0C, // 45 consecutive values out of range
|
||||
TSL2591_PERSIST_50 = 0x0D, // 50 consecutive values out of range
|
||||
TSL2591_PERSIST_55 = 0x0E, // 55 consecutive values out of range
|
||||
TSL2591_PERSIST_60 = 0x0F, // 60 consecutive values out of range
|
||||
} tsl2591Persist_t;
|
||||
|
||||
/// Enumeration for the sensor gain
|
||||
typedef enum {
|
||||
TSL2591_GAIN_LOW = 0x00, /// low gain (1x)
|
||||
TSL2591_GAIN_MED = 0x10, /// medium gain (25x)
|
||||
TSL2591_GAIN_HIGH = 0x20, /// medium gain (428x)
|
||||
TSL2591_GAIN_MAX = 0x30, /// max gain (9876x)
|
||||
} tsl2591Gain_t;
|
||||
|
||||
enum ChipModel{
|
||||
ChipModel_UNKNOWN = 0,
|
||||
ChipModel_TSL25911_REV0 = 0x50
|
||||
};
|
||||
|
||||
|
||||
TSL25911(TwoWire* i2c): m_initialized(false), gain(TSL2591_GAIN_MED), integration(TSL2591_INTEGRATIONTIME_500MS),i2c(i2c){}
|
||||
TSL25911(TwoWire* i2c, tsl2591Gain_t _gain,tsl2591IntegrationTime_t _integration) : m_initialized(false),gain(_gain),integration(_integration),i2c(i2c) {}
|
||||
|
||||
ChipModel chipModel();
|
||||
|
||||
bool begin();
|
||||
bool reset();
|
||||
|
||||
uint16_t lumV();
|
||||
uint16_t lumIR();
|
||||
uint16_t lumF();
|
||||
float lumLux();
|
||||
void read(uint16_t& v, uint16_t& ir, uint16_t& f, float& lux);
|
||||
|
||||
|
||||
protected:
|
||||
bool Initialize();
|
||||
|
||||
|
||||
private:
|
||||
bool m_initialized;
|
||||
ChipModel m_chip_model;
|
||||
TwoWire* i2c;
|
||||
tsl2591Gain_t gain;
|
||||
tsl2591IntegrationTime_t integration;
|
||||
|
||||
static const uint8_t REG_ENABLE = 0xA0 | 0x00;
|
||||
static const uint8_t REG_CTRL = 0xA0 | 0x01;
|
||||
|
||||
static const uint8_t PID_ADDR = 0xA0 | 0x11;
|
||||
static const uint8_t ID_ADDR = 0xA0 | 0x12;
|
||||
|
||||
static const uint8_t DEVICE_STATUS = 0xA0 | 0x13; // Internal Status
|
||||
static const uint8_t CHAN0_LOW = 0xA0 | 0x14; // Channel 0 data, low byte
|
||||
static const uint8_t CHAN0_HIGH = 0xA0 | 0x15; // Channel 0 data, high byte
|
||||
static const uint8_t CHAN1_LOW = 0xA0 | 0x16; // Channel 1 data, low byte
|
||||
static const uint8_t CHAN1_HIGH = 0xA0 | 0x17; // Channel 1 data, high byte
|
||||
|
||||
|
||||
float again();
|
||||
float atime();
|
||||
|
||||
|
||||
bool ReadChipID();
|
||||
|
||||
bool ReadRegister(uint8_t addr,uint8_t data[],uint8_t length);
|
||||
bool ReadData(uint32_t data[SENSOR_DATA_LENGTH]);
|
||||
|
||||
void WriteSettings();
|
||||
bool WriteRegister(uint8_t addr,uint8_t data);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
129
src/sensor/environment.cpp
Normal file
129
src/sensor/environment.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
EnvironmentCalculations.cpp
|
||||
Copyright (C) 2016 Tyler Glenn
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
Written: Dec 30 2015.
|
||||
Last Updated: Dec 23 2017.
|
||||
This header must be included in any derived code or copies of the code.
|
||||
*/
|
||||
#include "environment.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <math.h>
|
||||
|
||||
#define hi_coeff1 -42.379
|
||||
#define hi_coeff2 2.04901523
|
||||
#define hi_coeff3 10.14333127
|
||||
#define hi_coeff4 -0.22475541
|
||||
#define hi_coeff5 -0.00683783
|
||||
#define hi_coeff6 -0.05481717
|
||||
#define hi_coeff7 0.00122874
|
||||
#define hi_coeff8 0.00085282
|
||||
#define hi_coeff9 -0.00000199
|
||||
|
||||
/****************************************************************/
|
||||
float EnvironmentCalculations::Altitude(float pressure,float referencePressure,float outdoorTemp){
|
||||
// Equation inverse to EquivalentSeaLevelPressure calculation.
|
||||
float altitude = NAN;
|
||||
if (!isnan(pressure) && !isnan(referencePressure) && !isnan(outdoorTemp)){
|
||||
altitude = pow(referencePressure / pressure, 0.190234) - 1;
|
||||
altitude *= ((outdoorTemp + 273.15) / 0.0065);
|
||||
}
|
||||
return altitude;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
float EnvironmentCalculations::AbsoluteHumidity(float temperature, float humidity){
|
||||
//taken from https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/
|
||||
//precision is about 0.1°C in range -30 to 35°C
|
||||
//August-Roche-Magnus 6.1094 exp(17.625 x T)/(T + 243.04)
|
||||
//Buck (1981) 6.1121 exp(17.502 x T)/(T + 240.97)
|
||||
//reference https://www.eas.ualberta.ca/jdwilson/EAS372_13/Vomel_CIRES_satvpformulae.html
|
||||
float temp = NAN;
|
||||
const float mw = 18.01534; // molar mass of water g/mol
|
||||
const float r = 8.31447215; // Universal gas constant J/mol/K
|
||||
|
||||
if (isnan(temperature) || isnan(humidity) ){
|
||||
return NAN;
|
||||
}
|
||||
|
||||
temp = pow(2.718281828, (17.67 * temperature) / (temperature + 243.5));
|
||||
|
||||
//return (6.112 * temp * humidity * 2.1674) / (273.15 + temperature); //simplified version
|
||||
return (6.112 * temp * humidity * mw) / ((273.15 + temperature) * r); //long version
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
//FYI: https://ehp.niehs.nih.gov/1206273/ in detail this flow graph: https://ehp.niehs.nih.gov/wp-content/uploads/2013/10/ehp.1206273.g003.png
|
||||
float EnvironmentCalculations::HeatIndex(float temperature,float humidity){
|
||||
float heatIndex(NAN);
|
||||
|
||||
if ( isnan(temperature) || isnan(humidity) ) {
|
||||
return heatIndex;
|
||||
}
|
||||
|
||||
temperature = (temperature * (9.0 / 5.0) + 32.0); /*conversion to [°F]*/
|
||||
|
||||
// Using both Rothfusz and Steadman's equations
|
||||
// http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml
|
||||
if (temperature <= 40) {
|
||||
heatIndex = temperature; //first red block
|
||||
}else{
|
||||
heatIndex = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + (humidity * 0.094)); //calculate A -- from the official site, not the flow graph
|
||||
|
||||
if (heatIndex >= 79) {
|
||||
/*
|
||||
* calculate B
|
||||
* the following calculation is optimized. Simply spoken, reduzed cpu-operations to minimize used ram and runtime.
|
||||
* Check the correctness with the following link:
|
||||
* http://www.wolframalpha.com/input/?source=nav&i=b%3D+x1+%2B+x2*T+%2B+x3*H+%2B+x4*T*H+%2B+x5*T*T+%2B+x6*H*H+%2B+x7*T*T*H+%2B+x8*T*H*H+%2B+x9*T*T*H*H
|
||||
*/
|
||||
heatIndex = hi_coeff1
|
||||
+ (hi_coeff2 + hi_coeff4 * humidity + temperature * (hi_coeff5 + hi_coeff7 * humidity)) * temperature
|
||||
+ (hi_coeff3 + humidity * (hi_coeff6 + temperature * (hi_coeff8 + hi_coeff9 * temperature))) * humidity;
|
||||
//third red block
|
||||
if ((humidity < 13) && (temperature >= 80.0) && (temperature <= 112.0)) {
|
||||
heatIndex -= ((13.0 - humidity) * 0.25) * sqrt((17.0 - abs(temperature - 95.0)) * 0.05882);
|
||||
}else if ((humidity > 85.0) && (temperature >= 80.0) && (temperature <= 87.0)){
|
||||
heatIndex += (0.02 * (humidity - 85.0) * (87.0 - temperature));
|
||||
}
|
||||
}
|
||||
}
|
||||
return (heatIndex - 32.0) * (5.0 / 9.0); /*conversion back to [°C]*/
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
float EnvironmentCalculations::EquivalentSeaLevelPressure(float altitude,float temp,float pres){
|
||||
float seaPress = NAN;
|
||||
if(!isnan(altitude) && !isnan(temp) && !isnan(pres)){
|
||||
seaPress = (pres / pow(1 - ((0.0065 *altitude) / (temp + (0.0065 *altitude) + 273.15)), 5.257));
|
||||
}
|
||||
return seaPress;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
float EnvironmentCalculations::DewPoint(float temp,float hum){
|
||||
// Equations courtesy of Brian McNoldy from http://andrew.rsmas.miami.edu;
|
||||
float dewPoint = NAN;
|
||||
|
||||
if(!isnan(temp) && !isnan(hum)){
|
||||
dewPoint = 243.04 * (log(hum/100.0) + ((17.625 * temp)/(243.04 + temp)))
|
||||
/(17.625 - log(hum/100.0) - ((17.625 * temp)/(243.04 + temp)));
|
||||
}
|
||||
|
||||
return dewPoint;
|
||||
}
|
||||
|
62
src/sensor/environment.h
Normal file
62
src/sensor/environment.h
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
#ifndef TG_ENVIRONMENT_CALCULATIONS_H
|
||||
#define TG_ENVIRONMENT_CALCULATIONS_H
|
||||
|
||||
namespace EnvironmentCalculations{
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// Calculate the altitude based on the pressure and temperature
|
||||
/// in temptUnit.
|
||||
/// @param pressure at the station in any units.
|
||||
/// @param altUnit meters or feet. default=AltitudeUnit_Meters
|
||||
/// @param referencePressure (usually pressure on MSL)
|
||||
/// in the same units as pressure. default=1013.25hPa (ISA)
|
||||
/// @param outdoorTemp temperature at the station in tempUnit
|
||||
/// default=15°C (ISA)
|
||||
/// @return Calculated Altitude in meters.
|
||||
float Altitude(
|
||||
float pressure,
|
||||
float referencePressure = 1013.25, // [hPa] ....ISA value
|
||||
float outdoorTemp = 15 // [°C] .... ISA value
|
||||
);
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// Calculate the heatindex based on the humidity and temperature
|
||||
/// in tempUnit.
|
||||
/// The formula based on the Heat Index Equation of the US National Weather Service
|
||||
/// http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml
|
||||
/// @param temperature in tempUnit
|
||||
/// @param humidity in percentage
|
||||
/// @return Calculated heatindex as float in TempUnit
|
||||
float HeatIndex(float temperature,float humidity);
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// Calculate the absolute humidity based on the relative humidity and temperature
|
||||
/// in tempUnit.
|
||||
/// the formula does work for values between -30°C and 35°C with 0.1°C precision
|
||||
/// @param temperature in tempUnit
|
||||
/// @param humidity in percentage
|
||||
/// @return Calculated absolute humidity in grams/m³
|
||||
float AbsoluteHumidity(float temperature, float humidity);
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// Convert current pressure to equivalent sea-level pressure.
|
||||
/// @param altitude in meters.
|
||||
/// @param temp in tempUnit.
|
||||
/// @param pressure at the station in any units.
|
||||
/// @return Equivalent pressure at sea level. The input pressure
|
||||
/// unit will determine the output
|
||||
/// pressure unit.
|
||||
float EquivalentSeaLevelPressure(float altitude,float temp,float pres);
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// Calculate the dew point based on the temperature in tempUnit
|
||||
/// and humidity.
|
||||
/// @param temp in tempUnit.
|
||||
/// @param hum in %.
|
||||
float DewPoint(float temp,float hum);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // TG_ENVIRONMENT_CALCULATIONS_H
|
41
src/sensor/sensor.cpp
Normal file
41
src/sensor/sensor.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
|
||||
#include "sensor.h"
|
||||
#include "environment.h"
|
||||
|
||||
|
||||
Sensor::Sensor(TwoWire* i2c){
|
||||
bme = new BME280(i2c);
|
||||
ltr = new LTR390(i2c);
|
||||
tsl = new TSL25911(i2c);
|
||||
sgp = new SGP40(i2c);
|
||||
pms = new PMSA003(i2c);
|
||||
}
|
||||
|
||||
void Sensor::TSL_init(void){tsl->begin();}
|
||||
void Sensor::BME_init(void){bme->begin();}
|
||||
void Sensor::ICM_init(void){}//Nothing to do afaik
|
||||
void Sensor::LTR_init(void){ltr->begin();}
|
||||
void Sensor::SGP_init(void){sgp->begin();}
|
||||
void Sensor::PMS_init(void){pms->begin();}
|
||||
|
||||
|
||||
void Sensor::BME_measure(){
|
||||
bme->read(pres, temp, hum);
|
||||
heatidx = EnvironmentCalculations::HeatIndex(temp,hum);
|
||||
}
|
||||
void Sensor::LTR_measure(){
|
||||
ltr->read(uv, uvi);
|
||||
}
|
||||
void Sensor::TSL_measure(void){
|
||||
tsl->read(light_vis, light_ir, light_full, light_lux);
|
||||
}
|
||||
void Sensor::ICM_measure(void){
|
||||
//Do realy care about this ????
|
||||
}
|
||||
void Sensor::SGP_measure(void){
|
||||
sgp->read(voci, temp, hum);
|
||||
}
|
||||
void Sensor::PMS_measure(void){
|
||||
pms->read(pmd);
|
||||
}
|
71
src/sensor/sensor.h
Normal file
71
src/sensor/sensor.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef SENSOR_H
|
||||
#define SENSOR_H
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
#include "environment.h"
|
||||
#include "dev/bme280.h"
|
||||
#include "dev/ltr390.h"
|
||||
#include "dev/icm20948.h"
|
||||
#include "dev/sgp40.h"
|
||||
#include "dev/tsl25911.h"
|
||||
|
||||
#include "dev/pmsa003.h"
|
||||
|
||||
|
||||
class Sensor
|
||||
{
|
||||
// user-accessible "public" interface
|
||||
public:
|
||||
Sensor(TwoWire* i2c);
|
||||
|
||||
float temp = 0;
|
||||
float pres = 0;
|
||||
float hum = 0;
|
||||
float heatidx = 0;
|
||||
|
||||
float light = 0;
|
||||
uint32_t uv = 0;
|
||||
uint32_t uvi = 0;
|
||||
|
||||
uint16_t light_full = 0;
|
||||
uint16_t light_vis = 0;
|
||||
uint16_t light_ir = 0;
|
||||
float light_lux = 0;
|
||||
|
||||
int32_t voci = 0;
|
||||
PM25_AQI_Data pmd = {0};
|
||||
|
||||
void TSL_init(void); //Light Sensor
|
||||
void BME_init(void); //Temp, Hum, Presssure
|
||||
void ICM_init(void); //motion,accel, gyro, magnet
|
||||
void LTR_init(void); //UV, AL
|
||||
void SGP_init(void); //VOC
|
||||
void PMS_init(void); //PM2.5 - PM10
|
||||
|
||||
void TSL_measure(void);
|
||||
void BME_measure(void);
|
||||
void ICM_measure(void);
|
||||
void LTR_measure(void);
|
||||
void SGP_measure(void);
|
||||
void PMS_measure(void);
|
||||
|
||||
void measure(){
|
||||
TSL_measure();
|
||||
BME_measure();
|
||||
ICM_measure();
|
||||
LTR_measure();
|
||||
SGP_measure();
|
||||
PMS_measure();
|
||||
}
|
||||
|
||||
private:
|
||||
BME280* bme = NULL;
|
||||
LTR390* ltr = NULL;
|
||||
TSL25911* tsl = NULL;
|
||||
SGP40* sgp = NULL;
|
||||
PMSA003* pms = NULL;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
804
src/sensor/voc.cpp
Normal file
804
src/sensor/voc.cpp
Normal file
@ -0,0 +1,804 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "voc.h"
|
||||
|
||||
/* The fixed point arithmetic parts of this code were originally created by
|
||||
* https://github.com/PetteriAimonen/libfixmath
|
||||
*/
|
||||
|
||||
/*!< the maximum value of fix16_t */
|
||||
#define FIX16_MAXIMUM 0x7FFFFFFF
|
||||
/*!< the minimum value of fix16_t */
|
||||
#define FIX16_MINIMUM 0x80000000
|
||||
/*!< the value used to indicate overflows when FIXMATH_NO_OVERFLOW is not
|
||||
* specified */
|
||||
#define FIX16_OVERFLOW 0x80000000
|
||||
/*!< fix16_t value of 1 */
|
||||
#define FIX16_ONE 0x00010000
|
||||
|
||||
inline fix16_t fix16_from_int(int32_t a) {
|
||||
return a * FIX16_ONE;
|
||||
}
|
||||
|
||||
inline int32_t fix16_cast_to_int(fix16_t a) {
|
||||
return (a >> 16);
|
||||
}
|
||||
|
||||
/*! Multiplies the two given fix16_t's and returns the result. */
|
||||
static fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1);
|
||||
|
||||
/*! Divides the first given fix16_t by the second and returns the result. */
|
||||
static fix16_t fix16_div(fix16_t inArg0, fix16_t inArg1);
|
||||
|
||||
/*! Returns the square root of the given fix16_t. */
|
||||
static fix16_t fix16_sqrt(fix16_t inValue);
|
||||
|
||||
/*! Returns the exponent (e^) of the given fix16_t. */
|
||||
static fix16_t fix16_exp(fix16_t inValue);
|
||||
|
||||
static fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1) {
|
||||
// Each argument is divided to 16-bit parts.
|
||||
// AB
|
||||
// * CD
|
||||
// -----------
|
||||
// BD 16 * 16 -> 32 bit products
|
||||
// CB
|
||||
// AD
|
||||
// AC
|
||||
// |----| 64 bit product
|
||||
int32_t A = (inArg0 >> 16), C = (inArg1 >> 16);
|
||||
uint32_t B = (inArg0 & 0xFFFF), D = (inArg1 & 0xFFFF);
|
||||
|
||||
int32_t AC = A * C;
|
||||
int32_t AD_CB = A * D + C * B;
|
||||
uint32_t BD = B * D;
|
||||
|
||||
int32_t product_hi = AC + (AD_CB >> 16);
|
||||
|
||||
// Handle carry from lower 32 bits to upper part of result.
|
||||
uint32_t ad_cb_temp = AD_CB << 16;
|
||||
uint32_t product_lo = BD + ad_cb_temp;
|
||||
if (product_lo < BD)
|
||||
product_hi++;
|
||||
|
||||
#ifndef FIXMATH_NO_OVERFLOW
|
||||
// The upper 17 bits should all be the same (the sign).
|
||||
if (product_hi >> 31 != product_hi >> 15)
|
||||
return FIX16_OVERFLOW;
|
||||
#endif
|
||||
|
||||
#ifdef FIXMATH_NO_ROUNDING
|
||||
return (product_hi << 16) | (product_lo >> 16);
|
||||
#else
|
||||
// Subtracting 0x8000 (= 0.5) and then using signed right shift
|
||||
// achieves proper rounding to result-1, except in the corner
|
||||
// case of negative numbers and lowest word = 0x8000.
|
||||
// To handle that, we also have to subtract 1 for negative numbers.
|
||||
uint32_t product_lo_tmp = product_lo;
|
||||
product_lo -= 0x8000;
|
||||
product_lo -= (uint32_t)product_hi >> 31;
|
||||
if (product_lo > product_lo_tmp)
|
||||
product_hi--;
|
||||
|
||||
// Discard the lowest 16 bits. Note that this is not exactly the same
|
||||
// as dividing by 0x10000. For example if product = -1, result will
|
||||
// also be -1 and not 0. This is compensated by adding +1 to the result
|
||||
// and compensating this in turn in the rounding above.
|
||||
fix16_t result = (product_hi << 16) | (product_lo >> 16);
|
||||
result += 1;
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static fix16_t fix16_div(fix16_t a, fix16_t b) {
|
||||
// This uses the basic binary restoring division algorithm.
|
||||
// It appears to be faster to do the whole division manually than
|
||||
// trying to compose a 64-bit divide out of 32-bit divisions on
|
||||
// platforms without hardware divide.
|
||||
|
||||
if (b == 0)
|
||||
return FIX16_MINIMUM;
|
||||
|
||||
uint32_t remainder = (a >= 0) ? a : (-a);
|
||||
uint32_t divider = (b >= 0) ? b : (-b);
|
||||
|
||||
uint32_t quotient = 0;
|
||||
uint32_t bit = 0x10000;
|
||||
|
||||
/* The algorithm requires D >= R */
|
||||
while (divider < remainder) {
|
||||
divider <<= 1;
|
||||
bit <<= 1;
|
||||
}
|
||||
|
||||
#ifndef FIXMATH_NO_OVERFLOW
|
||||
if (!bit)
|
||||
return FIX16_OVERFLOW;
|
||||
#endif
|
||||
|
||||
if (divider & 0x80000000) {
|
||||
// Perform one step manually to avoid overflows later.
|
||||
// We know that divider's bottom bit is 0 here.
|
||||
if (remainder >= divider) {
|
||||
quotient |= bit;
|
||||
remainder -= divider;
|
||||
}
|
||||
divider >>= 1;
|
||||
bit >>= 1;
|
||||
}
|
||||
|
||||
/* Main division loop */
|
||||
while (bit && remainder) {
|
||||
if (remainder >= divider) {
|
||||
quotient |= bit;
|
||||
remainder -= divider;
|
||||
}
|
||||
|
||||
remainder <<= 1;
|
||||
bit >>= 1;
|
||||
}
|
||||
|
||||
#ifndef FIXMATH_NO_ROUNDING
|
||||
if (remainder >= divider) {
|
||||
quotient++;
|
||||
}
|
||||
#endif
|
||||
|
||||
fix16_t result = quotient;
|
||||
|
||||
/* Figure out the sign of result */
|
||||
if ((a ^ b) & 0x80000000) {
|
||||
#ifndef FIXMATH_NO_OVERFLOW
|
||||
if (result == FIX16_MINIMUM)
|
||||
return FIX16_OVERFLOW;
|
||||
#endif
|
||||
|
||||
result = -result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static fix16_t fix16_sqrt(fix16_t x) {
|
||||
// It is assumed that x is not negative
|
||||
|
||||
uint32_t num = x;
|
||||
uint32_t result = 0;
|
||||
uint32_t bit;
|
||||
uint8_t n;
|
||||
|
||||
bit = (uint32_t)1 << 30;
|
||||
while (bit > num)
|
||||
bit >>= 2;
|
||||
|
||||
// The main part is executed twice, in order to avoid
|
||||
// using 64 bit values in computations.
|
||||
for (n = 0; n < 2; n++) {
|
||||
// First we get the top 24 bits of the answer.
|
||||
while (bit) {
|
||||
if (num >= result + bit) {
|
||||
num -= result + bit;
|
||||
result = (result >> 1) + bit;
|
||||
} else {
|
||||
result = (result >> 1);
|
||||
}
|
||||
bit >>= 2;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
// Then process it again to get the lowest 8 bits.
|
||||
if (num > 65535) {
|
||||
// The remainder 'num' is too large to be shifted left
|
||||
// by 16, so we have to add 1 to result manually and
|
||||
// adjust 'num' accordingly.
|
||||
// num = a - (result + 0.5)^2
|
||||
// = num + result^2 - (result + 0.5)^2
|
||||
// = num - result - 0.5
|
||||
num -= result;
|
||||
num = (num << 16) - 0x8000;
|
||||
result = (result << 16) + 0x8000;
|
||||
} else {
|
||||
num <<= 16;
|
||||
result <<= 16;
|
||||
}
|
||||
|
||||
bit = 1 << 14;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef FIXMATH_NO_ROUNDING
|
||||
// Finally, if next bit would have been 1, round the result upwards.
|
||||
if (num > result) {
|
||||
result++;
|
||||
}
|
||||
#endif
|
||||
|
||||
return (fix16_t)result;
|
||||
}
|
||||
|
||||
static fix16_t fix16_exp(fix16_t x) {
|
||||
// Function to approximate exp(); optimized more for code size than speed
|
||||
|
||||
// exp(x) for x = +/- {1, 1/8, 1/64, 1/512}
|
||||
#define NUM_EXP_VALUES 4
|
||||
static const fix16_t exp_pos_values[NUM_EXP_VALUES] = {
|
||||
F16(2.7182818), F16(1.1331485), F16(1.0157477), F16(1.0019550)};
|
||||
static const fix16_t exp_neg_values[NUM_EXP_VALUES] = {
|
||||
F16(0.3678794), F16(0.8824969), F16(0.9844964), F16(0.9980488)};
|
||||
const fix16_t* exp_values;
|
||||
|
||||
fix16_t res, arg;
|
||||
uint16_t i;
|
||||
|
||||
if (x >= F16(10.3972))
|
||||
return FIX16_MAXIMUM;
|
||||
if (x <= F16(-11.7835))
|
||||
return 0;
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
exp_values = exp_neg_values;
|
||||
} else {
|
||||
exp_values = exp_pos_values;
|
||||
}
|
||||
|
||||
res = FIX16_ONE;
|
||||
arg = FIX16_ONE;
|
||||
for (i = 0; i < NUM_EXP_VALUES; i++) {
|
||||
while (x >= arg) {
|
||||
res = fix16_mul(res, exp_values[i]);
|
||||
x -= arg;
|
||||
}
|
||||
arg >>= 3;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void VocAlgorithm__init_instances(VocAlgorithmParams* params);
|
||||
static void
|
||||
VocAlgorithm__mean_variance_estimator__init(VocAlgorithmParams* params);
|
||||
static void VocAlgorithm__mean_variance_estimator___init_instances(
|
||||
VocAlgorithmParams* params);
|
||||
static void VocAlgorithm__mean_variance_estimator__set_parameters(
|
||||
VocAlgorithmParams* params, fix16_t std_initial,
|
||||
fix16_t tau_mean_variance_hours, fix16_t gating_max_duration_minutes);
|
||||
static void
|
||||
VocAlgorithm__mean_variance_estimator__set_states(VocAlgorithmParams* params,
|
||||
fix16_t mean, fix16_t std,
|
||||
fix16_t uptime_gamma);
|
||||
static fix16_t
|
||||
VocAlgorithm__mean_variance_estimator__get_std(VocAlgorithmParams* params);
|
||||
static fix16_t
|
||||
VocAlgorithm__mean_variance_estimator__get_mean(VocAlgorithmParams* params);
|
||||
static void VocAlgorithm__mean_variance_estimator___calculate_gamma(
|
||||
VocAlgorithmParams* params, fix16_t voc_index_from_prior);
|
||||
static void VocAlgorithm__mean_variance_estimator__process(
|
||||
VocAlgorithmParams* params, fix16_t sraw, fix16_t voc_index_from_prior);
|
||||
static void VocAlgorithm__mean_variance_estimator___sigmoid__init(
|
||||
VocAlgorithmParams* params);
|
||||
static void VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
|
||||
VocAlgorithmParams* params, fix16_t L, fix16_t X0, fix16_t K);
|
||||
static fix16_t VocAlgorithm__mean_variance_estimator___sigmoid__process(
|
||||
VocAlgorithmParams* params, fix16_t sample);
|
||||
static void VocAlgorithm__mox_model__init(VocAlgorithmParams* params);
|
||||
static void VocAlgorithm__mox_model__set_parameters(VocAlgorithmParams* params,
|
||||
fix16_t SRAW_STD,
|
||||
fix16_t SRAW_MEAN);
|
||||
static fix16_t VocAlgorithm__mox_model__process(VocAlgorithmParams* params,
|
||||
fix16_t sraw);
|
||||
static void VocAlgorithm__sigmoid_scaled__init(VocAlgorithmParams* params);
|
||||
static void
|
||||
VocAlgorithm__sigmoid_scaled__set_parameters(VocAlgorithmParams* params,
|
||||
fix16_t offset);
|
||||
static fix16_t VocAlgorithm__sigmoid_scaled__process(VocAlgorithmParams* params,
|
||||
fix16_t sample);
|
||||
static void VocAlgorithm__adaptive_lowpass__init(VocAlgorithmParams* params);
|
||||
static void
|
||||
VocAlgorithm__adaptive_lowpass__set_parameters(VocAlgorithmParams* params);
|
||||
static fix16_t
|
||||
VocAlgorithm__adaptive_lowpass__process(VocAlgorithmParams* params,
|
||||
fix16_t sample);
|
||||
|
||||
void VocAlgorithm_init(VocAlgorithmParams* params) {
|
||||
|
||||
params->mVoc_Index_Offset = F16(VocAlgorithm_VOC_INDEX_OFFSET_DEFAULT);
|
||||
params->mTau_Mean_Variance_Hours =
|
||||
F16(VocAlgorithm_TAU_MEAN_VARIANCE_HOURS);
|
||||
params->mGating_Max_Duration_Minutes =
|
||||
F16(VocAlgorithm_GATING_MAX_DURATION_MINUTES);
|
||||
params->mSraw_Std_Initial = F16(VocAlgorithm_SRAW_STD_INITIAL);
|
||||
params->mUptime = F16(0.);
|
||||
params->mSraw = F16(0.);
|
||||
params->mVoc_Index = 0;
|
||||
VocAlgorithm__init_instances(params);
|
||||
}
|
||||
|
||||
static void VocAlgorithm__init_instances(VocAlgorithmParams* params) {
|
||||
|
||||
VocAlgorithm__mean_variance_estimator__init(params);
|
||||
VocAlgorithm__mean_variance_estimator__set_parameters(
|
||||
params, params->mSraw_Std_Initial, params->mTau_Mean_Variance_Hours,
|
||||
params->mGating_Max_Duration_Minutes);
|
||||
VocAlgorithm__mox_model__init(params);
|
||||
VocAlgorithm__mox_model__set_parameters(
|
||||
params, VocAlgorithm__mean_variance_estimator__get_std(params),
|
||||
VocAlgorithm__mean_variance_estimator__get_mean(params));
|
||||
VocAlgorithm__sigmoid_scaled__init(params);
|
||||
VocAlgorithm__sigmoid_scaled__set_parameters(params,
|
||||
params->mVoc_Index_Offset);
|
||||
VocAlgorithm__adaptive_lowpass__init(params);
|
||||
VocAlgorithm__adaptive_lowpass__set_parameters(params);
|
||||
}
|
||||
|
||||
void VocAlgorithm_get_states(VocAlgorithmParams* params, int32_t* state0,
|
||||
int32_t* state1) {
|
||||
|
||||
*state0 = VocAlgorithm__mean_variance_estimator__get_mean(params);
|
||||
*state1 = VocAlgorithm__mean_variance_estimator__get_std(params);
|
||||
return;
|
||||
}
|
||||
|
||||
void VocAlgorithm_set_states(VocAlgorithmParams* params, int32_t state0,
|
||||
int32_t state1) {
|
||||
|
||||
VocAlgorithm__mean_variance_estimator__set_states(
|
||||
params, state0, state1, F16(VocAlgorithm_PERSISTENCE_UPTIME_GAMMA));
|
||||
params->mSraw = state0;
|
||||
}
|
||||
|
||||
void VocAlgorithm_set_tuning_parameters(VocAlgorithmParams* params,
|
||||
int32_t voc_index_offset,
|
||||
int32_t learning_time_hours,
|
||||
int32_t gating_max_duration_minutes,
|
||||
int32_t std_initial) {
|
||||
|
||||
params->mVoc_Index_Offset = (fix16_from_int(voc_index_offset));
|
||||
params->mTau_Mean_Variance_Hours = (fix16_from_int(learning_time_hours));
|
||||
params->mGating_Max_Duration_Minutes =
|
||||
(fix16_from_int(gating_max_duration_minutes));
|
||||
params->mSraw_Std_Initial = (fix16_from_int(std_initial));
|
||||
VocAlgorithm__init_instances(params);
|
||||
}
|
||||
|
||||
void VocAlgorithm_process(VocAlgorithmParams* params, int32_t sraw,
|
||||
int32_t* voc_index) {
|
||||
|
||||
if ((params->mUptime <= F16(VocAlgorithm_INITIAL_BLACKOUT))) {
|
||||
params->mUptime =
|
||||
(params->mUptime + F16(VocAlgorithm_SAMPLING_INTERVAL));
|
||||
} else {
|
||||
if (((sraw > 0) && (sraw < 65000))) {
|
||||
if ((sraw < 20001)) {
|
||||
sraw = 20001;
|
||||
} else if ((sraw > 52767)) {
|
||||
sraw = 52767;
|
||||
}
|
||||
params->mSraw = (fix16_from_int((sraw - 20000)));
|
||||
}
|
||||
params->mVoc_Index =
|
||||
VocAlgorithm__mox_model__process(params, params->mSraw);
|
||||
params->mVoc_Index =
|
||||
VocAlgorithm__sigmoid_scaled__process(params, params->mVoc_Index);
|
||||
params->mVoc_Index =
|
||||
VocAlgorithm__adaptive_lowpass__process(params, params->mVoc_Index);
|
||||
if ((params->mVoc_Index < F16(0.5))) {
|
||||
params->mVoc_Index = F16(0.5);
|
||||
}
|
||||
if ((params->mSraw > F16(0.))) {
|
||||
VocAlgorithm__mean_variance_estimator__process(
|
||||
params, params->mSraw, params->mVoc_Index);
|
||||
VocAlgorithm__mox_model__set_parameters(
|
||||
params, VocAlgorithm__mean_variance_estimator__get_std(params),
|
||||
VocAlgorithm__mean_variance_estimator__get_mean(params));
|
||||
}
|
||||
}
|
||||
*voc_index = (fix16_cast_to_int((params->mVoc_Index + F16(0.5))));
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
VocAlgorithm__mean_variance_estimator__init(VocAlgorithmParams* params) {
|
||||
|
||||
VocAlgorithm__mean_variance_estimator__set_parameters(params, F16(0.),
|
||||
F16(0.), F16(0.));
|
||||
VocAlgorithm__mean_variance_estimator___init_instances(params);
|
||||
}
|
||||
|
||||
static void VocAlgorithm__mean_variance_estimator___init_instances(
|
||||
VocAlgorithmParams* params) {
|
||||
|
||||
VocAlgorithm__mean_variance_estimator___sigmoid__init(params);
|
||||
}
|
||||
|
||||
static void VocAlgorithm__mean_variance_estimator__set_parameters(
|
||||
VocAlgorithmParams* params, fix16_t std_initial,
|
||||
fix16_t tau_mean_variance_hours, fix16_t gating_max_duration_minutes) {
|
||||
|
||||
params->m_Mean_Variance_Estimator__Gating_Max_Duration_Minutes =
|
||||
gating_max_duration_minutes;
|
||||
params->m_Mean_Variance_Estimator___Initialized = false;
|
||||
params->m_Mean_Variance_Estimator___Mean = F16(0.);
|
||||
params->m_Mean_Variance_Estimator___Sraw_Offset = F16(0.);
|
||||
params->m_Mean_Variance_Estimator___Std = std_initial;
|
||||
params->m_Mean_Variance_Estimator___Gamma =
|
||||
(fix16_div(F16((VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING *
|
||||
(VocAlgorithm_SAMPLING_INTERVAL / 3600.))),
|
||||
(tau_mean_variance_hours +
|
||||
F16((VocAlgorithm_SAMPLING_INTERVAL / 3600.)))));
|
||||
params->m_Mean_Variance_Estimator___Gamma_Initial_Mean =
|
||||
F16(((VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING *
|
||||
VocAlgorithm_SAMPLING_INTERVAL) /
|
||||
(VocAlgorithm_TAU_INITIAL_MEAN + VocAlgorithm_SAMPLING_INTERVAL)));
|
||||
params->m_Mean_Variance_Estimator___Gamma_Initial_Variance = F16(
|
||||
((VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING *
|
||||
VocAlgorithm_SAMPLING_INTERVAL) /
|
||||
(VocAlgorithm_TAU_INITIAL_VARIANCE + VocAlgorithm_SAMPLING_INTERVAL)));
|
||||
params->m_Mean_Variance_Estimator__Gamma_Mean = F16(0.);
|
||||
params->m_Mean_Variance_Estimator__Gamma_Variance = F16(0.);
|
||||
params->m_Mean_Variance_Estimator___Uptime_Gamma = F16(0.);
|
||||
params->m_Mean_Variance_Estimator___Uptime_Gating = F16(0.);
|
||||
params->m_Mean_Variance_Estimator___Gating_Duration_Minutes = F16(0.);
|
||||
}
|
||||
|
||||
static void
|
||||
VocAlgorithm__mean_variance_estimator__set_states(VocAlgorithmParams* params,
|
||||
fix16_t mean, fix16_t std,
|
||||
fix16_t uptime_gamma) {
|
||||
|
||||
params->m_Mean_Variance_Estimator___Mean = mean;
|
||||
params->m_Mean_Variance_Estimator___Std = std;
|
||||
params->m_Mean_Variance_Estimator___Uptime_Gamma = uptime_gamma;
|
||||
params->m_Mean_Variance_Estimator___Initialized = true;
|
||||
}
|
||||
|
||||
static fix16_t
|
||||
VocAlgorithm__mean_variance_estimator__get_std(VocAlgorithmParams* params) {
|
||||
|
||||
return params->m_Mean_Variance_Estimator___Std;
|
||||
}
|
||||
|
||||
static fix16_t
|
||||
VocAlgorithm__mean_variance_estimator__get_mean(VocAlgorithmParams* params) {
|
||||
|
||||
return (params->m_Mean_Variance_Estimator___Mean +
|
||||
params->m_Mean_Variance_Estimator___Sraw_Offset);
|
||||
}
|
||||
|
||||
static void VocAlgorithm__mean_variance_estimator___calculate_gamma(
|
||||
VocAlgorithmParams* params, fix16_t voc_index_from_prior) {
|
||||
|
||||
fix16_t uptime_limit;
|
||||
fix16_t sigmoid_gamma_mean;
|
||||
fix16_t gamma_mean;
|
||||
fix16_t gating_threshold_mean;
|
||||
fix16_t sigmoid_gating_mean;
|
||||
fix16_t sigmoid_gamma_variance;
|
||||
fix16_t gamma_variance;
|
||||
fix16_t gating_threshold_variance;
|
||||
fix16_t sigmoid_gating_variance;
|
||||
|
||||
uptime_limit = F16((VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__FIX16_MAX -
|
||||
VocAlgorithm_SAMPLING_INTERVAL));
|
||||
if ((params->m_Mean_Variance_Estimator___Uptime_Gamma < uptime_limit)) {
|
||||
params->m_Mean_Variance_Estimator___Uptime_Gamma =
|
||||
(params->m_Mean_Variance_Estimator___Uptime_Gamma +
|
||||
F16(VocAlgorithm_SAMPLING_INTERVAL));
|
||||
}
|
||||
if ((params->m_Mean_Variance_Estimator___Uptime_Gating < uptime_limit)) {
|
||||
params->m_Mean_Variance_Estimator___Uptime_Gating =
|
||||
(params->m_Mean_Variance_Estimator___Uptime_Gating +
|
||||
F16(VocAlgorithm_SAMPLING_INTERVAL));
|
||||
}
|
||||
VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
|
||||
params, F16(1.), F16(VocAlgorithm_INIT_DURATION_MEAN),
|
||||
F16(VocAlgorithm_INIT_TRANSITION_MEAN));
|
||||
sigmoid_gamma_mean =
|
||||
VocAlgorithm__mean_variance_estimator___sigmoid__process(
|
||||
params, params->m_Mean_Variance_Estimator___Uptime_Gamma);
|
||||
gamma_mean =
|
||||
(params->m_Mean_Variance_Estimator___Gamma +
|
||||
(fix16_mul((params->m_Mean_Variance_Estimator___Gamma_Initial_Mean -
|
||||
params->m_Mean_Variance_Estimator___Gamma),
|
||||
sigmoid_gamma_mean)));
|
||||
gating_threshold_mean =
|
||||
(F16(VocAlgorithm_GATING_THRESHOLD) +
|
||||
(fix16_mul(
|
||||
F16((VocAlgorithm_GATING_THRESHOLD_INITIAL -
|
||||
VocAlgorithm_GATING_THRESHOLD)),
|
||||
VocAlgorithm__mean_variance_estimator___sigmoid__process(
|
||||
params, params->m_Mean_Variance_Estimator___Uptime_Gating))));
|
||||
VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
|
||||
params, F16(1.), gating_threshold_mean,
|
||||
F16(VocAlgorithm_GATING_THRESHOLD_TRANSITION));
|
||||
sigmoid_gating_mean =
|
||||
VocAlgorithm__mean_variance_estimator___sigmoid__process(
|
||||
params, voc_index_from_prior);
|
||||
params->m_Mean_Variance_Estimator__Gamma_Mean =
|
||||
(fix16_mul(sigmoid_gating_mean, gamma_mean));
|
||||
VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
|
||||
params, F16(1.), F16(VocAlgorithm_INIT_DURATION_VARIANCE),
|
||||
F16(VocAlgorithm_INIT_TRANSITION_VARIANCE));
|
||||
sigmoid_gamma_variance =
|
||||
VocAlgorithm__mean_variance_estimator___sigmoid__process(
|
||||
params, params->m_Mean_Variance_Estimator___Uptime_Gamma);
|
||||
gamma_variance =
|
||||
(params->m_Mean_Variance_Estimator___Gamma +
|
||||
(fix16_mul(
|
||||
(params->m_Mean_Variance_Estimator___Gamma_Initial_Variance -
|
||||
params->m_Mean_Variance_Estimator___Gamma),
|
||||
(sigmoid_gamma_variance - sigmoid_gamma_mean))));
|
||||
gating_threshold_variance =
|
||||
(F16(VocAlgorithm_GATING_THRESHOLD) +
|
||||
(fix16_mul(
|
||||
F16((VocAlgorithm_GATING_THRESHOLD_INITIAL -
|
||||
VocAlgorithm_GATING_THRESHOLD)),
|
||||
VocAlgorithm__mean_variance_estimator___sigmoid__process(
|
||||
params, params->m_Mean_Variance_Estimator___Uptime_Gating))));
|
||||
VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
|
||||
params, F16(1.), gating_threshold_variance,
|
||||
F16(VocAlgorithm_GATING_THRESHOLD_TRANSITION));
|
||||
sigmoid_gating_variance =
|
||||
VocAlgorithm__mean_variance_estimator___sigmoid__process(
|
||||
params, voc_index_from_prior);
|
||||
params->m_Mean_Variance_Estimator__Gamma_Variance =
|
||||
(fix16_mul(sigmoid_gating_variance, gamma_variance));
|
||||
params->m_Mean_Variance_Estimator___Gating_Duration_Minutes =
|
||||
(params->m_Mean_Variance_Estimator___Gating_Duration_Minutes +
|
||||
(fix16_mul(F16((VocAlgorithm_SAMPLING_INTERVAL / 60.)),
|
||||
((fix16_mul((F16(1.) - sigmoid_gating_mean),
|
||||
F16((1. + VocAlgorithm_GATING_MAX_RATIO)))) -
|
||||
F16(VocAlgorithm_GATING_MAX_RATIO)))));
|
||||
if ((params->m_Mean_Variance_Estimator___Gating_Duration_Minutes <
|
||||
F16(0.))) {
|
||||
params->m_Mean_Variance_Estimator___Gating_Duration_Minutes = F16(0.);
|
||||
}
|
||||
if ((params->m_Mean_Variance_Estimator___Gating_Duration_Minutes >
|
||||
params->m_Mean_Variance_Estimator__Gating_Max_Duration_Minutes)) {
|
||||
params->m_Mean_Variance_Estimator___Uptime_Gating = F16(0.);
|
||||
}
|
||||
}
|
||||
|
||||
static void VocAlgorithm__mean_variance_estimator__process(
|
||||
VocAlgorithmParams* params, fix16_t sraw, fix16_t voc_index_from_prior) {
|
||||
|
||||
fix16_t delta_sgp;
|
||||
fix16_t c;
|
||||
fix16_t additional_scaling;
|
||||
|
||||
if ((params->m_Mean_Variance_Estimator___Initialized == false)) {
|
||||
params->m_Mean_Variance_Estimator___Initialized = true;
|
||||
params->m_Mean_Variance_Estimator___Sraw_Offset = sraw;
|
||||
params->m_Mean_Variance_Estimator___Mean = F16(0.);
|
||||
} else {
|
||||
if (((params->m_Mean_Variance_Estimator___Mean >= F16(100.)) ||
|
||||
(params->m_Mean_Variance_Estimator___Mean <= F16(-100.)))) {
|
||||
params->m_Mean_Variance_Estimator___Sraw_Offset =
|
||||
(params->m_Mean_Variance_Estimator___Sraw_Offset +
|
||||
params->m_Mean_Variance_Estimator___Mean);
|
||||
params->m_Mean_Variance_Estimator___Mean = F16(0.);
|
||||
}
|
||||
sraw = (sraw - params->m_Mean_Variance_Estimator___Sraw_Offset);
|
||||
VocAlgorithm__mean_variance_estimator___calculate_gamma(
|
||||
params, voc_index_from_prior);
|
||||
delta_sgp = (fix16_div(
|
||||
(sraw - params->m_Mean_Variance_Estimator___Mean),
|
||||
F16(VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING)));
|
||||
if ((delta_sgp < F16(0.))) {
|
||||
c = (params->m_Mean_Variance_Estimator___Std - delta_sgp);
|
||||
} else {
|
||||
c = (params->m_Mean_Variance_Estimator___Std + delta_sgp);
|
||||
}
|
||||
additional_scaling = F16(1.);
|
||||
if ((c > F16(1440.))) {
|
||||
additional_scaling = F16(4.);
|
||||
}
|
||||
params->m_Mean_Variance_Estimator___Std = (fix16_mul(
|
||||
fix16_sqrt((fix16_mul(
|
||||
additional_scaling,
|
||||
(F16(VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING) -
|
||||
params->m_Mean_Variance_Estimator__Gamma_Variance)))),
|
||||
fix16_sqrt((
|
||||
(fix16_mul(
|
||||
params->m_Mean_Variance_Estimator___Std,
|
||||
(fix16_div(
|
||||
params->m_Mean_Variance_Estimator___Std,
|
||||
(fix16_mul(
|
||||
F16(VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING),
|
||||
additional_scaling)))))) +
|
||||
(fix16_mul(
|
||||
(fix16_div(
|
||||
(fix16_mul(
|
||||
params->m_Mean_Variance_Estimator__Gamma_Variance,
|
||||
delta_sgp)),
|
||||
additional_scaling)),
|
||||
delta_sgp))))));
|
||||
params->m_Mean_Variance_Estimator___Mean =
|
||||
(params->m_Mean_Variance_Estimator___Mean +
|
||||
(fix16_mul(params->m_Mean_Variance_Estimator__Gamma_Mean,
|
||||
delta_sgp)));
|
||||
}
|
||||
}
|
||||
|
||||
static void VocAlgorithm__mean_variance_estimator___sigmoid__init(
|
||||
VocAlgorithmParams* params) {
|
||||
|
||||
VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
|
||||
params, F16(0.), F16(0.), F16(0.));
|
||||
}
|
||||
|
||||
static void VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
|
||||
VocAlgorithmParams* params, fix16_t L, fix16_t X0, fix16_t K) {
|
||||
|
||||
params->m_Mean_Variance_Estimator___Sigmoid__L = L;
|
||||
params->m_Mean_Variance_Estimator___Sigmoid__K = K;
|
||||
params->m_Mean_Variance_Estimator___Sigmoid__X0 = X0;
|
||||
}
|
||||
|
||||
static fix16_t VocAlgorithm__mean_variance_estimator___sigmoid__process(
|
||||
VocAlgorithmParams* params, fix16_t sample) {
|
||||
|
||||
fix16_t x;
|
||||
|
||||
x = (fix16_mul(params->m_Mean_Variance_Estimator___Sigmoid__K,
|
||||
(sample - params->m_Mean_Variance_Estimator___Sigmoid__X0)));
|
||||
if ((x < F16(-50.))) {
|
||||
return params->m_Mean_Variance_Estimator___Sigmoid__L;
|
||||
} else if ((x > F16(50.))) {
|
||||
return F16(0.);
|
||||
} else {
|
||||
return (fix16_div(params->m_Mean_Variance_Estimator___Sigmoid__L,
|
||||
(F16(1.) + fix16_exp(x))));
|
||||
}
|
||||
}
|
||||
|
||||
static void VocAlgorithm__mox_model__init(VocAlgorithmParams* params) {
|
||||
|
||||
VocAlgorithm__mox_model__set_parameters(params, F16(1.), F16(0.));
|
||||
}
|
||||
|
||||
static void VocAlgorithm__mox_model__set_parameters(VocAlgorithmParams* params,
|
||||
fix16_t SRAW_STD,
|
||||
fix16_t SRAW_MEAN) {
|
||||
|
||||
params->m_Mox_Model__Sraw_Std = SRAW_STD;
|
||||
params->m_Mox_Model__Sraw_Mean = SRAW_MEAN;
|
||||
}
|
||||
|
||||
static fix16_t VocAlgorithm__mox_model__process(VocAlgorithmParams* params,
|
||||
fix16_t sraw) {
|
||||
|
||||
return (fix16_mul((fix16_div((sraw - params->m_Mox_Model__Sraw_Mean),
|
||||
(-(params->m_Mox_Model__Sraw_Std +
|
||||
F16(VocAlgorithm_SRAW_STD_BONUS))))),
|
||||
F16(VocAlgorithm_VOC_INDEX_GAIN)));
|
||||
}
|
||||
|
||||
static void VocAlgorithm__sigmoid_scaled__init(VocAlgorithmParams* params) {
|
||||
|
||||
VocAlgorithm__sigmoid_scaled__set_parameters(params, F16(0.));
|
||||
}
|
||||
|
||||
static void
|
||||
VocAlgorithm__sigmoid_scaled__set_parameters(VocAlgorithmParams* params,
|
||||
fix16_t offset) {
|
||||
|
||||
params->m_Sigmoid_Scaled__Offset = offset;
|
||||
}
|
||||
|
||||
static fix16_t VocAlgorithm__sigmoid_scaled__process(VocAlgorithmParams* params,
|
||||
fix16_t sample) {
|
||||
|
||||
fix16_t x;
|
||||
fix16_t shift;
|
||||
|
||||
x = (fix16_mul(F16(VocAlgorithm_SIGMOID_K),
|
||||
(sample - F16(VocAlgorithm_SIGMOID_X0))));
|
||||
if ((x < F16(-50.))) {
|
||||
return F16(VocAlgorithm_SIGMOID_L);
|
||||
} else if ((x > F16(50.))) {
|
||||
return F16(0.);
|
||||
} else {
|
||||
if ((sample >= F16(0.))) {
|
||||
shift = (fix16_div(
|
||||
(F16(VocAlgorithm_SIGMOID_L) -
|
||||
(fix16_mul(F16(5.), params->m_Sigmoid_Scaled__Offset))),
|
||||
F16(4.)));
|
||||
return ((fix16_div((F16(VocAlgorithm_SIGMOID_L) + shift),
|
||||
(F16(1.) + fix16_exp(x)))) -
|
||||
shift);
|
||||
} else {
|
||||
return (fix16_mul(
|
||||
(fix16_div(params->m_Sigmoid_Scaled__Offset,
|
||||
F16(VocAlgorithm_VOC_INDEX_OFFSET_DEFAULT))),
|
||||
(fix16_div(F16(VocAlgorithm_SIGMOID_L),
|
||||
(F16(1.) + fix16_exp(x))))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void VocAlgorithm__adaptive_lowpass__init(VocAlgorithmParams* params) {
|
||||
|
||||
VocAlgorithm__adaptive_lowpass__set_parameters(params);
|
||||
}
|
||||
|
||||
static void
|
||||
VocAlgorithm__adaptive_lowpass__set_parameters(VocAlgorithmParams* params) {
|
||||
|
||||
params->m_Adaptive_Lowpass__A1 =
|
||||
F16((VocAlgorithm_SAMPLING_INTERVAL /
|
||||
(VocAlgorithm_LP_TAU_FAST + VocAlgorithm_SAMPLING_INTERVAL)));
|
||||
params->m_Adaptive_Lowpass__A2 =
|
||||
F16((VocAlgorithm_SAMPLING_INTERVAL /
|
||||
(VocAlgorithm_LP_TAU_SLOW + VocAlgorithm_SAMPLING_INTERVAL)));
|
||||
params->m_Adaptive_Lowpass___Initialized = false;
|
||||
}
|
||||
|
||||
static fix16_t
|
||||
VocAlgorithm__adaptive_lowpass__process(VocAlgorithmParams* params,
|
||||
fix16_t sample) {
|
||||
|
||||
fix16_t abs_delta;
|
||||
fix16_t F1;
|
||||
fix16_t tau_a;
|
||||
fix16_t a3;
|
||||
|
||||
if ((params->m_Adaptive_Lowpass___Initialized == false)) {
|
||||
params->m_Adaptive_Lowpass___X1 = sample;
|
||||
params->m_Adaptive_Lowpass___X2 = sample;
|
||||
params->m_Adaptive_Lowpass___X3 = sample;
|
||||
params->m_Adaptive_Lowpass___Initialized = true;
|
||||
}
|
||||
params->m_Adaptive_Lowpass___X1 =
|
||||
((fix16_mul((F16(1.) - params->m_Adaptive_Lowpass__A1),
|
||||
params->m_Adaptive_Lowpass___X1)) +
|
||||
(fix16_mul(params->m_Adaptive_Lowpass__A1, sample)));
|
||||
params->m_Adaptive_Lowpass___X2 =
|
||||
((fix16_mul((F16(1.) - params->m_Adaptive_Lowpass__A2),
|
||||
params->m_Adaptive_Lowpass___X2)) +
|
||||
(fix16_mul(params->m_Adaptive_Lowpass__A2, sample)));
|
||||
abs_delta =
|
||||
(params->m_Adaptive_Lowpass___X1 - params->m_Adaptive_Lowpass___X2);
|
||||
if ((abs_delta < F16(0.))) {
|
||||
abs_delta = (-abs_delta);
|
||||
}
|
||||
F1 = fix16_exp((fix16_mul(F16(VocAlgorithm_LP_ALPHA), abs_delta)));
|
||||
tau_a =
|
||||
((fix16_mul(F16((VocAlgorithm_LP_TAU_SLOW - VocAlgorithm_LP_TAU_FAST)),
|
||||
F1)) +
|
||||
F16(VocAlgorithm_LP_TAU_FAST));
|
||||
a3 = (fix16_div(F16(VocAlgorithm_SAMPLING_INTERVAL),
|
||||
(F16(VocAlgorithm_SAMPLING_INTERVAL) + tau_a)));
|
||||
params->m_Adaptive_Lowpass___X3 =
|
||||
((fix16_mul((F16(1.) - a3), params->m_Adaptive_Lowpass___X3)) +
|
||||
(fix16_mul(a3, sample)));
|
||||
return params->m_Adaptive_Lowpass___X3;
|
||||
}
|
185
src/sensor/voc.h
Normal file
185
src/sensor/voc.h
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef VOCALGORITHM_H_
|
||||
#define VOCALGORITHM_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#define SENSIRION_I2C_CLOCK_PERIOD_USEC 10
|
||||
|
||||
/* The fixed point arithmetic parts of this code were originally created by
|
||||
* https://github.com/PetteriAimonen/libfixmath
|
||||
*/
|
||||
|
||||
typedef int32_t fix16_t;
|
||||
|
||||
#define F16(x) \
|
||||
((fix16_t)(((x) >= 0) ? ((x)*65536.0 + 0.5) : ((x)*65536.0 - 0.5)))
|
||||
|
||||
#define VocAlgorithm_SAMPLING_INTERVAL (1.)
|
||||
#define VocAlgorithm_INITIAL_BLACKOUT (45.)
|
||||
#define VocAlgorithm_VOC_INDEX_GAIN (230.)
|
||||
#define VocAlgorithm_SRAW_STD_INITIAL (50.)
|
||||
#define VocAlgorithm_SRAW_STD_BONUS (220.)
|
||||
#define VocAlgorithm_TAU_MEAN_VARIANCE_HOURS (12.)
|
||||
#define VocAlgorithm_TAU_INITIAL_MEAN (20.)
|
||||
#define VocAlgorithm_INIT_DURATION_MEAN ((3600. * 0.75))
|
||||
#define VocAlgorithm_INIT_TRANSITION_MEAN (0.01)
|
||||
#define VocAlgorithm_TAU_INITIAL_VARIANCE (2500.)
|
||||
#define VocAlgorithm_INIT_DURATION_VARIANCE ((3600. * 1.45))
|
||||
#define VocAlgorithm_INIT_TRANSITION_VARIANCE (0.01)
|
||||
#define VocAlgorithm_GATING_THRESHOLD (340.)
|
||||
#define VocAlgorithm_GATING_THRESHOLD_INITIAL (510.)
|
||||
#define VocAlgorithm_GATING_THRESHOLD_TRANSITION (0.09)
|
||||
#define VocAlgorithm_GATING_MAX_DURATION_MINUTES ((60. * 3.))
|
||||
#define VocAlgorithm_GATING_MAX_RATIO (0.3)
|
||||
#define VocAlgorithm_SIGMOID_L (500.)
|
||||
#define VocAlgorithm_SIGMOID_K (-0.0065)
|
||||
#define VocAlgorithm_SIGMOID_X0 (213.)
|
||||
#define VocAlgorithm_VOC_INDEX_OFFSET_DEFAULT (100.)
|
||||
#define VocAlgorithm_LP_TAU_FAST (20.0)
|
||||
#define VocAlgorithm_LP_TAU_SLOW (500.0)
|
||||
#define VocAlgorithm_LP_ALPHA (-0.2)
|
||||
#define VocAlgorithm_PERSISTENCE_UPTIME_GAMMA ((3. * 3600.))
|
||||
#define VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING (64.)
|
||||
#define VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__FIX16_MAX (32767.)
|
||||
|
||||
/**
|
||||
* Struct to hold all the states of the VOC algorithm.
|
||||
*/
|
||||
typedef struct {
|
||||
fix16_t mVoc_Index_Offset;
|
||||
fix16_t mTau_Mean_Variance_Hours;
|
||||
fix16_t mGating_Max_Duration_Minutes;
|
||||
fix16_t mSraw_Std_Initial;
|
||||
fix16_t mUptime;
|
||||
fix16_t mSraw;
|
||||
fix16_t mVoc_Index;
|
||||
fix16_t m_Mean_Variance_Estimator__Gating_Max_Duration_Minutes;
|
||||
bool m_Mean_Variance_Estimator___Initialized;
|
||||
fix16_t m_Mean_Variance_Estimator___Mean;
|
||||
fix16_t m_Mean_Variance_Estimator___Sraw_Offset;
|
||||
fix16_t m_Mean_Variance_Estimator___Std;
|
||||
fix16_t m_Mean_Variance_Estimator___Gamma;
|
||||
fix16_t m_Mean_Variance_Estimator___Gamma_Initial_Mean;
|
||||
fix16_t m_Mean_Variance_Estimator___Gamma_Initial_Variance;
|
||||
fix16_t m_Mean_Variance_Estimator__Gamma_Mean;
|
||||
fix16_t m_Mean_Variance_Estimator__Gamma_Variance;
|
||||
fix16_t m_Mean_Variance_Estimator___Uptime_Gamma;
|
||||
fix16_t m_Mean_Variance_Estimator___Uptime_Gating;
|
||||
fix16_t m_Mean_Variance_Estimator___Gating_Duration_Minutes;
|
||||
fix16_t m_Mean_Variance_Estimator___Sigmoid__L;
|
||||
fix16_t m_Mean_Variance_Estimator___Sigmoid__K;
|
||||
fix16_t m_Mean_Variance_Estimator___Sigmoid__X0;
|
||||
fix16_t m_Mox_Model__Sraw_Std;
|
||||
fix16_t m_Mox_Model__Sraw_Mean;
|
||||
fix16_t m_Sigmoid_Scaled__Offset;
|
||||
fix16_t m_Adaptive_Lowpass__A1;
|
||||
fix16_t m_Adaptive_Lowpass__A2;
|
||||
bool m_Adaptive_Lowpass___Initialized;
|
||||
fix16_t m_Adaptive_Lowpass___X1;
|
||||
fix16_t m_Adaptive_Lowpass___X2;
|
||||
fix16_t m_Adaptive_Lowpass___X3;
|
||||
} VocAlgorithmParams;
|
||||
|
||||
/**
|
||||
* Initialize the VOC algorithm parameters. Call this once at the beginning or
|
||||
* whenever the sensor stopped measurements.
|
||||
* @param params Pointer to the VocAlgorithmParams struct
|
||||
*/
|
||||
void VocAlgorithm_init(VocAlgorithmParams* params);
|
||||
|
||||
/**
|
||||
* Get current algorithm states. Retrieved values can be used in
|
||||
* VocAlgorithm_set_states() to resume operation after a short interruption,
|
||||
* skipping initial learning phase. This feature can only be used after at least
|
||||
* 3 hours of continuous operation.
|
||||
* @param params Pointer to the VocAlgorithmParams struct
|
||||
* @param state0 State0 to be stored
|
||||
* @param state1 State1 to be stored
|
||||
*/
|
||||
void VocAlgorithm_get_states(VocAlgorithmParams* params, int32_t* state0,
|
||||
int32_t* state1);
|
||||
|
||||
/**
|
||||
* Set previously retrieved algorithm states to resume operation after a short
|
||||
* interruption, skipping initial learning phase. This feature should not be
|
||||
* used after inerruptions of more than 10 minutes. Call this once after
|
||||
* VocAlgorithm_init() and the optional VocAlgorithm_set_tuning_parameters(), if
|
||||
* desired. Otherwise, the algorithm will start with initial learning phase.
|
||||
* @param params Pointer to the VocAlgorithmParams struct
|
||||
* @param state0 State0 to be restored
|
||||
* @param state1 State1 to be restored
|
||||
*/
|
||||
void VocAlgorithm_set_states(VocAlgorithmParams* params, int32_t state0,
|
||||
int32_t state1);
|
||||
|
||||
/**
|
||||
* Set parameters to customize the VOC algorithm. Call this once after
|
||||
* VocAlgorithm_init(), if desired. Otherwise, the default values will be used.
|
||||
*
|
||||
* @param params Pointer to the VocAlgorithmParams struct
|
||||
* @param voc_index_offset VOC index representing typical (average)
|
||||
* conditions. Range 1..250, default 100
|
||||
* @param learning_time_hours Time constant of long-term estimator.
|
||||
* Past events will be forgotten after about
|
||||
* twice the learning time.
|
||||
* Range 1..72 [hours], default 12 [hours]
|
||||
* @param gating_max_duration_minutes Maximum duration of gating (freeze of
|
||||
* estimator during high VOC index signal).
|
||||
* 0 (no gating) or range 1..720 [minutes],
|
||||
* default 180 [minutes]
|
||||
* @param std_initial Initial estimate for standard deviation.
|
||||
* Lower value boosts events during initial
|
||||
* learning period, but may result in larger
|
||||
* device-to-device variations.
|
||||
* Range 10..500, default 50
|
||||
*/
|
||||
void VocAlgorithm_set_tuning_parameters(VocAlgorithmParams* params,
|
||||
int32_t voc_index_offset,
|
||||
int32_t learning_time_hours,
|
||||
int32_t gating_max_duration_minutes,
|
||||
int32_t std_initial);
|
||||
|
||||
/**
|
||||
* Calculate the VOC index value from the raw sensor value.
|
||||
*
|
||||
* @param params Pointer to the VocAlgorithmParams struct
|
||||
* @param sraw Raw value from the SGP40 sensor
|
||||
* @param voc_index Calculated VOC index value from the raw sensor value. Zero
|
||||
* during initial blackout period and 1..500 afterwards
|
||||
*/
|
||||
void VocAlgorithm_process(VocAlgorithmParams* params, int32_t sraw,
|
||||
int32_t* voc_index);
|
||||
|
||||
#endif /* VOCALGORITHM_H_ */
|
16
src/time/time.h
Normal file
16
src/time/time.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef time_h
|
||||
#define time_h
|
||||
|
||||
struct strDateTime
|
||||
{
|
||||
byte hour;
|
||||
byte minute;
|
||||
byte second;
|
||||
int year;
|
||||
byte month;
|
||||
byte day;
|
||||
byte dayofWeek;
|
||||
boolean valid;
|
||||
};
|
||||
|
||||
#endif
|
112
src/touch/gt1151.cpp
Normal file
112
src/touch/gt1151.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
#include "gt1151.h"
|
||||
|
||||
#define GT1151_RESET_PIN 02
|
||||
#define GT1151_INT_PIN 15
|
||||
|
||||
GT1151_Dev Dev_Now, Dev_Old;
|
||||
uint8_t GT_Gesture_Mode = 0;
|
||||
|
||||
volatile uint8_t gtIRQ = 0;
|
||||
void IRAM_ATTR _gt_irq_handler() {
|
||||
noInterrupts();
|
||||
gtIRQ = 1;
|
||||
interrupts();
|
||||
}
|
||||
|
||||
GT1151::GT1151(TwoWire* i2c){ wire = i2c;}
|
||||
|
||||
void GT1151::setHandler(void (*handler)(int8_t, GTPoint*)) {
|
||||
touchHandler = handler;
|
||||
}
|
||||
|
||||
|
||||
void GT1151::armIRQ() {
|
||||
attachInterrupt(GT1151_INT_PIN, _gt_irq_handler, RISING);
|
||||
}
|
||||
|
||||
void GT1151::onIRQ() {
|
||||
int16_t contacts = readInput((GTPoint *) dev.points);
|
||||
dev.holding = contacts > 0 && dev.pressing;
|
||||
dev.pressing = contacts > 0;
|
||||
if (contacts < 0) return;
|
||||
if (contacts > 0) touchHandler(contacts, (GTPoint *)dev.points);
|
||||
WriteRegister(GT1151_READ_COORD_ADDR, 0x00);
|
||||
}
|
||||
|
||||
|
||||
int16_t GT1151::readInput(GTPoint* points) {
|
||||
uint8_t* data = static_cast<uint8_t*>(static_cast<void*>(points));
|
||||
int touch_num;
|
||||
uint8_t regState;
|
||||
int error = !ReadRegister(GT1151_READ_COORD_ADDR, ®State, 1);
|
||||
if (!(regState & 0x80)) return -1;
|
||||
|
||||
|
||||
touch_num = regState & 0x0f;
|
||||
if(touch_num > 5) return -1;
|
||||
if (touch_num <= 0) return touch_num;
|
||||
|
||||
error = !ReadRegister(GT1151_READ_POINTS, data, sizeof(GTPoint) * touch_num);
|
||||
if (error) return -1;
|
||||
for(int i = 0; i< touch_num; i++) {
|
||||
points[i].x = lowByte(points[i].x)<<8 | highByte(points[i].x);
|
||||
points[i].y = lowByte(points[i].y)<<8 | highByte(points[i].y);
|
||||
points[i].a = lowByte(points[i].a)<<8 | highByte(points[i].a);
|
||||
}
|
||||
return touch_num;
|
||||
}
|
||||
|
||||
|
||||
void GT1151::Reset(void){
|
||||
pinMode(GT1151_INT_PIN, OUTPUT);
|
||||
pinMode(GT1151_INT_PIN, INPUT);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
void GT1151::ReadVersion(void){
|
||||
uint8_t buf[4] = {};
|
||||
ReadRegister(GT1151_REG_ID, buf, 4);
|
||||
}
|
||||
|
||||
void GT1151::begin(void){
|
||||
delay(500);
|
||||
Reset();
|
||||
ReadVersion();
|
||||
armIRQ();
|
||||
}
|
||||
|
||||
void GT1151::update() {
|
||||
|
||||
noInterrupts();
|
||||
uint8_t irq = gtIRQ;
|
||||
gtIRQ = 0;
|
||||
interrupts();
|
||||
if (irq) onIRQ();
|
||||
else dev.pressing = false;
|
||||
}
|
||||
|
||||
bool GT1151::WriteRegister(uint16_t addr, uint8_t data){
|
||||
wire->beginTransmission(GT1151_ADDRESS);
|
||||
wire->write(highByte(addr));
|
||||
wire->write(lowByte(addr));
|
||||
wire->write(data);
|
||||
wire->endTransmission();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GT1151::ReadRegister(uint16_t addr,uint8_t data[],uint8_t length){
|
||||
uint8_t ord(0);
|
||||
|
||||
wire->beginTransmission(GT1151_ADDRESS);
|
||||
wire->write(highByte(addr));
|
||||
wire->write(lowByte(addr));
|
||||
wire->endTransmission();
|
||||
|
||||
wire->requestFrom(static_cast<uint8_t>(GT1151_ADDRESS), length);
|
||||
|
||||
while(wire->available()){
|
||||
data[ord++] = wire->read();
|
||||
}
|
||||
|
||||
return ord == length;
|
||||
}
|
67
src/touch/gt1151.h
Normal file
67
src/touch/gt1151.h
Normal file
@ -0,0 +1,67 @@
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
#ifndef __GT1151_H
|
||||
#define __GT1151_H
|
||||
|
||||
#define GT1151_ADDRESS 0x14
|
||||
#define GT1151_ADDRESS_28 0x14
|
||||
#define GT1151_ADDRESS_BA 0x5D
|
||||
|
||||
#define CT_MAX_TOUCH 5
|
||||
|
||||
|
||||
#define GT1151_REG_CMD 0x8040
|
||||
|
||||
|
||||
#define GT1151_REG_DATA 0x8140
|
||||
#define GT1151_REG_ID 0x8140
|
||||
|
||||
#define GT1151_READ_COORD_ADDR 0x814E
|
||||
#define GT1151_READ_POINTS 0x814F
|
||||
|
||||
|
||||
struct GTPoint {
|
||||
uint8_t id;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t a;
|
||||
};
|
||||
|
||||
typedef struct{
|
||||
bool holding;
|
||||
bool pressing;
|
||||
GTPoint points[CT_MAX_TOUCH];
|
||||
|
||||
}GT1151_Dev;
|
||||
|
||||
|
||||
class GT1151{
|
||||
public:
|
||||
GT1151_Dev dev;
|
||||
|
||||
GT1151(TwoWire* i2c);
|
||||
|
||||
void update(void);
|
||||
void begin(void);
|
||||
void Gesture(void);
|
||||
void setHandler(void (*handler)(int8_t, GTPoint*));
|
||||
|
||||
private:
|
||||
void (*touchHandler)(int8_t, GTPoint*);
|
||||
TwoWire* wire;
|
||||
|
||||
void Reset(void);
|
||||
|
||||
void armIRQ(void);
|
||||
void onIRQ(void);
|
||||
int16_t readInput(GTPoint* points);
|
||||
|
||||
void ReadVersion(void);
|
||||
uint8_t Scan(void);
|
||||
|
||||
bool WriteRegister(uint16_t addr, uint8_t data);
|
||||
bool ReadRegister(uint16_t addr,uint8_t data[],uint8_t length);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user