mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-06 11:36:51 +03:00
Merge branch 'main' into mqtt-add-ValidateServerCert-Parameter
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.16.0)
|
||||
|
||||
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common components/esp-tflite-micro)
|
||||
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common components/esp-tflite-micro components/esp-protocols/components/mdns)
|
||||
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version.cpp
|
||||
|
||||
1
code/components/esp-protocols
Submodule
1
code/components/esp-protocols
Submodule
Submodule code/components/esp-protocols added at 9b74256b51
@@ -1,27 +1,53 @@
|
||||
/********************************************************************************
|
||||
* https://github.com/RoboticsBrno/SmartLeds
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 RoboticsBrno (RobotikaBrno)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation 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
|
||||
* furnished 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 FOR 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 "Color.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
|
||||
// Int -> fixed point
|
||||
int up( int x ) { return x * 255; }
|
||||
int up(int x) { return x * 255; }
|
||||
|
||||
} // namespace
|
||||
|
||||
int iRgbSqrt( int num ) {
|
||||
int iRgbSqrt(int num) {
|
||||
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
|
||||
assert( "sqrt input should be non-negative" && num >= 0 );
|
||||
assert( "sqrt input should no exceed 16 bits" && num <= 0xFFFF );
|
||||
assert("sqrt input should be non-negative" && num >= 0);
|
||||
assert("sqrt input should no exceed 16 bits" && num <= 0xFFFF);
|
||||
int res = 0;
|
||||
int bit = 1 << 16;
|
||||
while ( bit > num )
|
||||
while (bit > num)
|
||||
bit >>= 2;
|
||||
while ( bit != 0 ) {
|
||||
if ( num >= res + bit ) {
|
||||
while (bit != 0) {
|
||||
if (num >= res + bit) {
|
||||
num -= res + bit;
|
||||
res = ( res >> 1 ) + bit;
|
||||
res = (res >> 1) + bit;
|
||||
} else
|
||||
res >>= 1;
|
||||
bit >>= 2;
|
||||
@@ -29,104 +55,133 @@ int iRgbSqrt( int num ) {
|
||||
return res;
|
||||
}
|
||||
|
||||
Rgb::Rgb( Hsv y ) {
|
||||
Rgb::Rgb(const Hsv& y) {
|
||||
// https://stackoverflow.com/questions/24152553/hsv-to-rgb-and-back-without-floating-point-math-in-python
|
||||
// greyscale
|
||||
if( y.s == 0 ) {
|
||||
if (y.s == 0) {
|
||||
r = g = b = y.v;
|
||||
return;
|
||||
}
|
||||
|
||||
const int region = y.h / 43;
|
||||
const int remainder = ( y.h - ( region * 43 ) ) * 6;
|
||||
const int remainder = (y.h - (region * 43)) * 6;
|
||||
|
||||
const int p = ( y.v * ( 255 - y.s ) ) >> 8;
|
||||
const int q = ( y.v * ( 255 - ( ( y.s * remainder ) >> 8 ) ) ) >> 8;
|
||||
const int t = ( y.v * ( 255 - ( ( y.s * (255 -remainder ) ) >> 8 ) ) ) >> 8;
|
||||
const int p = (y.v * (255 - y.s)) >> 8;
|
||||
const int q = (y.v * (255 - ((y.s * remainder) >> 8))) >> 8;
|
||||
const int t = (y.v * (255 - ((y.s * (255 - remainder)) >> 8))) >> 8;
|
||||
|
||||
switch( region ) {
|
||||
case 0: r = y.v; g = t; b = p; break;
|
||||
case 1: r = q; g = y.v; b = p; break;
|
||||
case 2: r = p; g = y.v; b = t; break;
|
||||
case 3: r = p; g = q; b = y.v; break;
|
||||
case 4: r = t; g = p; b = y.v; break;
|
||||
case 5: r = y.v; g = p; b = q; break;
|
||||
default: __builtin_trap();
|
||||
switch (region) {
|
||||
case 0:
|
||||
r = y.v;
|
||||
g = t;
|
||||
b = p;
|
||||
break;
|
||||
case 1:
|
||||
r = q;
|
||||
g = y.v;
|
||||
b = p;
|
||||
break;
|
||||
case 2:
|
||||
r = p;
|
||||
g = y.v;
|
||||
b = t;
|
||||
break;
|
||||
case 3:
|
||||
r = p;
|
||||
g = q;
|
||||
b = y.v;
|
||||
break;
|
||||
case 4:
|
||||
r = t;
|
||||
g = p;
|
||||
b = y.v;
|
||||
break;
|
||||
case 5:
|
||||
r = y.v;
|
||||
g = p;
|
||||
b = q;
|
||||
break;
|
||||
default:
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
a = y.a;
|
||||
}
|
||||
|
||||
Rgb& Rgb::operator=( Hsv hsv ) {
|
||||
Rgb r{ hsv };
|
||||
swap( r );
|
||||
Rgb& Rgb::operator=(const Hsv& hsv) {
|
||||
Rgb r { hsv };
|
||||
swap(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Rgb Rgb::operator+( Rgb in ) const {
|
||||
Rgb Rgb::operator+(const Rgb& in) const {
|
||||
auto copy = *this;
|
||||
copy += in;
|
||||
return copy;
|
||||
}
|
||||
|
||||
Rgb& Rgb::operator+=( Rgb in ) {
|
||||
Rgb& Rgb::operator+=(const Rgb& in) {
|
||||
unsigned int red = r + in.r;
|
||||
r = ( red < 255 ) ? red : 255;
|
||||
r = (red < 255) ? red : 255;
|
||||
unsigned int green = g + in.g;
|
||||
g = ( green < 255 ) ? green : 255;
|
||||
g = (green < 255) ? green : 255;
|
||||
unsigned int blue = b + in.b;
|
||||
b = ( blue < 255 ) ? blue : 255;
|
||||
b = (blue < 255) ? blue : 255;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Rgb& Rgb::blend( Rgb in ) {
|
||||
unsigned int inAlpha = in.a * ( 255 - a );
|
||||
Rgb Rgb::operator-(const Rgb& in) const {
|
||||
auto copy = *this;
|
||||
copy -= in;
|
||||
return copy;
|
||||
}
|
||||
|
||||
Rgb& Rgb::operator-=(const Rgb& in) {
|
||||
r = (in.r > r) ? 0 : r - in.r;
|
||||
g = (in.g > g) ? 0 : g - in.g;
|
||||
b = (in.b > b) ? 0 : b - in.b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Rgb& Rgb::blend(const Rgb& in) {
|
||||
unsigned int inAlpha = in.a * (255 - a);
|
||||
unsigned int alpha = a + inAlpha;
|
||||
r = iRgbSqrt( ( ( r * r * a ) + ( in.r * in.r * inAlpha ) ) / alpha );
|
||||
g = iRgbSqrt( ( ( g * g * a ) + ( in.g * in.g * inAlpha ) ) / alpha );
|
||||
b = iRgbSqrt( ( ( b * b * a ) + ( in.b * in.b * inAlpha ) ) / alpha );
|
||||
r = iRgbSqrt(((r * r * a) + (in.r * in.r * inAlpha)) / alpha);
|
||||
g = iRgbSqrt(((g * g * a) + (in.g * in.g * inAlpha)) / alpha);
|
||||
b = iRgbSqrt(((b * b * a) + (in.b * in.b * inAlpha)) / alpha);
|
||||
a = alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8_t IRAM_ATTR Rgb::getGrb( int idx ) {
|
||||
switch ( idx ) {
|
||||
case 0: return g;
|
||||
case 1: return r;
|
||||
case 2: return b;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
Hsv::Hsv( Rgb r ) {
|
||||
int min = std::min( r.r, std::min( r.g, r.b ) );
|
||||
int max = std::max( r.r, std::max( r.g, r.b ) );
|
||||
Hsv::Hsv(const Rgb& r) {
|
||||
int min = std::min(r.r, std::min(r.g, r.b));
|
||||
int max = std::max(r.r, std::max(r.g, r.b));
|
||||
int chroma = max - min;
|
||||
|
||||
v = max;
|
||||
if ( chroma == 0 ) {
|
||||
if (chroma == 0) {
|
||||
h = s = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
s = up( chroma ) / max;
|
||||
s = up(chroma) / max;
|
||||
int hh;
|
||||
if ( max == r.r )
|
||||
hh = ( up( int( r.g ) - int( r.b ) ) ) / chroma / 6;
|
||||
else if ( max == r.g )
|
||||
hh = 255 / 3 + ( up( int( r.b ) - int( r.r ) ) ) / chroma / 6;
|
||||
if (max == r.r)
|
||||
hh = (up(int(r.g) - int(r.b))) / chroma / 6;
|
||||
else if (max == r.g)
|
||||
hh = 255 / 3 + (up(int(r.b) - int(r.r))) / chroma / 6;
|
||||
else
|
||||
hh = 2 * 255 / 3 + ( up( int( r.r ) - int( r.g ) ) ) / chroma / 6;
|
||||
hh = 2 * 255 / 3 + (up(int(r.r) - int(r.g))) / chroma / 6;
|
||||
|
||||
if ( hh < 0 )
|
||||
if (hh < 0)
|
||||
hh += 255;
|
||||
h = hh;
|
||||
|
||||
a = r.a;
|
||||
}
|
||||
|
||||
Hsv& Hsv::operator=( Rgb rgb ) {
|
||||
Hsv h{ rgb };
|
||||
swap( h );
|
||||
Hsv& Hsv::operator=(const Rgb& rgb) {
|
||||
Hsv h { rgb };
|
||||
swap(h);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1,51 +1,90 @@
|
||||
/********************************************************************************
|
||||
* https://github.com/RoboticsBrno/SmartLeds
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 RoboticsBrno (RobotikaBrno)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation 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
|
||||
* furnished 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 FOR 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.
|
||||
*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef COLOR_H
|
||||
#define COLOR_H
|
||||
|
||||
#include <cstdint>
|
||||
#include "esp_attr.h"
|
||||
#include <cstdint>
|
||||
union Hsv;
|
||||
|
||||
union Rgb {
|
||||
struct __attribute__ ((packed)) {
|
||||
uint8_t r, g, b, a;
|
||||
struct __attribute__((packed)) {
|
||||
uint8_t g, r, b, a;
|
||||
};
|
||||
uint32_t value;
|
||||
|
||||
Rgb( uint8_t r = 0, uint8_t g = 0, uint8_t b = 0, uint8_t a = 255 ) : r( r ), g( g ), b( b ), a( a ) {}
|
||||
Rgb( Hsv c );
|
||||
Rgb& operator=( Rgb rgb ) { swap( rgb ); return *this; }
|
||||
Rgb& operator=( Hsv hsv );
|
||||
Rgb operator+( Rgb in ) const;
|
||||
Rgb& operator+=( Rgb in );
|
||||
bool operator==( Rgb in ) const { return in.value == value; }
|
||||
Rgb& blend( Rgb in );
|
||||
void swap( Rgb& o ) { value = o.value; }
|
||||
Rgb(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0, uint8_t a = 255)
|
||||
: g(g)
|
||||
, r(r)
|
||||
, b(b)
|
||||
, a(a) {}
|
||||
Rgb(const Hsv& c);
|
||||
Rgb(const Rgb&) = default;
|
||||
Rgb& operator=(const Rgb& rgb) {
|
||||
swap(rgb);
|
||||
return *this;
|
||||
}
|
||||
Rgb& operator=(const Hsv& hsv);
|
||||
Rgb operator+(const Rgb& in) const;
|
||||
Rgb& operator+=(const Rgb& in);
|
||||
Rgb operator-(const Rgb& in) const;
|
||||
Rgb& operator-=(const Rgb& in);
|
||||
bool operator==(const Rgb& in) const { return in.value == value; }
|
||||
Rgb& blend(const Rgb& in);
|
||||
void swap(const Rgb& o) { value = o.value; }
|
||||
void linearize() {
|
||||
r = channelGamma(r);
|
||||
g = channelGamma(g);
|
||||
b = channelGamma(b);
|
||||
}
|
||||
|
||||
uint8_t IRAM_ATTR getGrb( int idx );
|
||||
|
||||
void stretchChannels( uint8_t maxR, uint8_t maxG, uint8_t maxB ) {
|
||||
r = stretch( r, maxR );
|
||||
g = stretch( g, maxG );
|
||||
b = stretch( b, maxB );
|
||||
inline uint8_t IRAM_ATTR getGrb(int idx) {
|
||||
switch (idx) {
|
||||
case 0:
|
||||
return g;
|
||||
case 1:
|
||||
return r;
|
||||
case 2:
|
||||
return b;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void stretchChannelsEvenly( uint8_t max ) {
|
||||
stretchChannels( max, max, max );
|
||||
void stretchChannels(uint8_t maxR, uint8_t maxG, uint8_t maxB) {
|
||||
r = stretch(r, maxR);
|
||||
g = stretch(g, maxG);
|
||||
b = stretch(b, maxB);
|
||||
}
|
||||
|
||||
void stretchChannelsEvenly(uint8_t max) { stretchChannels(max, max, max); }
|
||||
|
||||
private:
|
||||
uint8_t stretch( int value, uint8_t max ) {
|
||||
return ( value * max ) >> 8;
|
||||
}
|
||||
uint8_t stretch(int value, uint8_t max) { return (value * max) >> 8; }
|
||||
|
||||
uint8_t channelGamma( int channel ) {
|
||||
uint8_t channelGamma(int channel) {
|
||||
/* The optimal gamma correction is x^2.8. However, this is expensive to
|
||||
* compute. Therefore, we use x^3 for gamma correction. Also, we add a
|
||||
* bias as the WS2812 LEDs do not turn on for values less than 4. */
|
||||
@@ -53,22 +92,27 @@ private:
|
||||
return channel;
|
||||
channel = channel * channel * channel * 251;
|
||||
channel >>= 24;
|
||||
return static_cast< uint8_t >( 4 + channel );
|
||||
return static_cast<uint8_t>(4 + channel);
|
||||
}
|
||||
};
|
||||
|
||||
union Hsv {
|
||||
struct __attribute__ ((packed)) {
|
||||
struct __attribute__((packed)) {
|
||||
uint8_t h, s, v, a;
|
||||
};
|
||||
uint32_t value;
|
||||
|
||||
Hsv( uint8_t h, uint8_t s = 0, uint8_t v = 0, uint8_t a = 255 ) : h( h ), s( s ), v( v ), a( a ) {}
|
||||
Hsv( Rgb r );
|
||||
Hsv& operator=( Hsv h ) { swap( h ); return *this; }
|
||||
Hsv& operator=( Rgb rgb );
|
||||
bool operator==( Hsv in ) const { return in.value == value; }
|
||||
void swap( Hsv& o ) { value = o.value; }
|
||||
Hsv(uint8_t h, uint8_t s = 0, uint8_t v = 0, uint8_t a = 255)
|
||||
: h(h)
|
||||
, s(s)
|
||||
, v(v)
|
||||
, a(a) {}
|
||||
Hsv(const Rgb& r);
|
||||
Hsv& operator=(const Hsv& h) {
|
||||
swap(h);
|
||||
return *this;
|
||||
}
|
||||
Hsv& operator=(const Rgb& rgb);
|
||||
bool operator==(const Hsv& in) const { return in.value == value; }
|
||||
void swap(const Hsv& o) { value = o.value; }
|
||||
};
|
||||
|
||||
#endif //COLOR_H
|
||||
|
||||
60
code/components/jomjol_controlGPIO/RmtDriver.h
Normal file
60
code/components/jomjol_controlGPIO/RmtDriver.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/********************************************************************************
|
||||
* https://github.com/RoboticsBrno/SmartLeds
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 RoboticsBrno (RobotikaBrno)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation 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
|
||||
* furnished 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 FOR 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.
|
||||
*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <esp_system.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(ESP_IDF_VERSION)
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
#define SMARTLEDS_NEW_RMT_DRIVER 1
|
||||
#else
|
||||
#define SMARTLEDS_NEW_RMT_DRIVER 0
|
||||
#endif
|
||||
#else
|
||||
#define SMARTLEDS_NEW_RMT_DRIVER 0
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct TimingParams {
|
||||
uint32_t T0H;
|
||||
uint32_t T1H;
|
||||
uint32_t T0L;
|
||||
uint32_t T1L;
|
||||
uint32_t TRS;
|
||||
};
|
||||
|
||||
using LedType = TimingParams;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#if SMARTLEDS_NEW_RMT_DRIVER
|
||||
#include "RmtDriver5.h"
|
||||
#else
|
||||
#include "RmtDriver4.h"
|
||||
#endif
|
||||
143
code/components/jomjol_controlGPIO/RmtDriver4.cpp
Normal file
143
code/components/jomjol_controlGPIO/RmtDriver4.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/********************************************************************************
|
||||
* https://github.com/RoboticsBrno/SmartLeds
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 RoboticsBrno (RobotikaBrno)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation 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
|
||||
* furnished 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 FOR 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 "RmtDriver4.h"
|
||||
|
||||
#if !SMARTLEDS_NEW_RMT_DRIVER
|
||||
#include "SmartLeds.h"
|
||||
|
||||
namespace detail {
|
||||
|
||||
// 8 still seems to work, but timings become marginal
|
||||
static const int DIVIDER = 4;
|
||||
// minimum time of a single RMT duration based on clock ns
|
||||
static const double RMT_DURATION_NS = 12.5;
|
||||
|
||||
RmtDriver::RmtDriver(const LedType& timing, int count, int pin, int channel_num, SemaphoreHandle_t finishedFlag)
|
||||
: _timing(timing)
|
||||
, _count(count)
|
||||
, _pin((gpio_num_t)pin)
|
||||
, _finishedFlag(finishedFlag)
|
||||
, _channel((rmt_channel_t)channel_num) {
|
||||
_bitToRmt[0].level0 = 1;
|
||||
_bitToRmt[0].level1 = 0;
|
||||
_bitToRmt[0].duration0 = _timing.T0H / (RMT_DURATION_NS * DIVIDER);
|
||||
_bitToRmt[0].duration1 = _timing.T0L / (RMT_DURATION_NS * DIVIDER);
|
||||
|
||||
_bitToRmt[1].level0 = 1;
|
||||
_bitToRmt[1].level1 = 0;
|
||||
_bitToRmt[1].duration0 = _timing.T1H / (RMT_DURATION_NS * DIVIDER);
|
||||
_bitToRmt[1].duration1 = _timing.T1L / (RMT_DURATION_NS * DIVIDER);
|
||||
}
|
||||
|
||||
esp_err_t RmtDriver::init() {
|
||||
rmt_config_t config = RMT_DEFAULT_CONFIG_TX(_pin, _channel);
|
||||
config.rmt_mode = RMT_MODE_TX;
|
||||
config.clk_div = DIVIDER;
|
||||
config.mem_block_num = 1;
|
||||
|
||||
return rmt_config(&config);
|
||||
}
|
||||
|
||||
esp_err_t RmtDriver::registerIsr(bool isFirstRegisteredChannel) {
|
||||
auto err = rmt_driver_install(_channel, 0,
|
||||
#if defined(CONFIG_RMT_ISR_IRAM_SAFE)
|
||||
ESP_INTR_FLAG_IRAM
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (isFirstRegisteredChannel) {
|
||||
rmt_register_tx_end_callback(txEndCallback, NULL);
|
||||
}
|
||||
|
||||
err = rmt_translator_init(_channel, translateSample);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
return rmt_translator_set_context(_channel, this);
|
||||
}
|
||||
|
||||
esp_err_t RmtDriver::unregisterIsr() { return rmt_driver_uninstall(_channel); }
|
||||
|
||||
void IRAM_ATTR RmtDriver::txEndCallback(rmt_channel_t channel, void* arg) {
|
||||
xSemaphoreGiveFromISR(SmartLed::ledForChannel(channel)->_finishedFlag, nullptr);
|
||||
}
|
||||
|
||||
void IRAM_ATTR RmtDriver::translateSample(const void* src, rmt_item32_t* dest, size_t src_size,
|
||||
size_t wanted_rmt_items_num, size_t* out_consumed_src_bytes, size_t* out_used_rmt_items) {
|
||||
RmtDriver* self;
|
||||
ESP_ERROR_CHECK(rmt_translator_get_context(out_used_rmt_items, (void**)&self));
|
||||
|
||||
const auto& _bitToRmt = self->_bitToRmt;
|
||||
const auto src_offset = self->_translatorSourceOffset;
|
||||
|
||||
auto* src_components = (const uint8_t*)src;
|
||||
size_t consumed_src_bytes = 0;
|
||||
size_t used_rmt_items = 0;
|
||||
|
||||
while (consumed_src_bytes < src_size && used_rmt_items + 7 < wanted_rmt_items_num) {
|
||||
uint8_t val = *src_components;
|
||||
|
||||
// each bit, from highest to lowest
|
||||
for (uint8_t j = 0; j != 8; j++, val <<= 1) {
|
||||
dest->val = _bitToRmt[val >> 7].val;
|
||||
++dest;
|
||||
}
|
||||
|
||||
used_rmt_items += 8;
|
||||
++src_components;
|
||||
++consumed_src_bytes;
|
||||
|
||||
// skip alpha byte
|
||||
if (((src_offset + consumed_src_bytes) % 4) == 3) {
|
||||
++src_components;
|
||||
++consumed_src_bytes;
|
||||
|
||||
// TRST delay after last pixel in strip
|
||||
if (consumed_src_bytes == src_size) {
|
||||
(dest - 1)->duration1 = self->_timing.TRS / (detail::RMT_DURATION_NS * detail::DIVIDER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self->_translatorSourceOffset = src_offset + consumed_src_bytes;
|
||||
*out_consumed_src_bytes = consumed_src_bytes;
|
||||
*out_used_rmt_items = used_rmt_items;
|
||||
}
|
||||
|
||||
esp_err_t RmtDriver::transmit(const Rgb* buffer) {
|
||||
static_assert(sizeof(Rgb) == 4); // The translator code above assumes RGB is 4 bytes
|
||||
|
||||
_translatorSourceOffset = 0;
|
||||
return rmt_write_sample(_channel, (const uint8_t*)buffer, _count * 4, false);
|
||||
}
|
||||
};
|
||||
#endif // !SMARTLEDS_NEW_RMT_DRIVER
|
||||
68
code/components/jomjol_controlGPIO/RmtDriver4.h
Normal file
68
code/components/jomjol_controlGPIO/RmtDriver4.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/********************************************************************************
|
||||
* https://github.com/RoboticsBrno/SmartLeds
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 RoboticsBrno (RobotikaBrno)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation 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
|
||||
* furnished 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 FOR 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.
|
||||
*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RmtDriver.h"
|
||||
|
||||
#if !SMARTLEDS_NEW_RMT_DRIVER
|
||||
#include "Color.h"
|
||||
#include <driver/rmt.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr const int CHANNEL_COUNT = RMT_CHANNEL_MAX;
|
||||
|
||||
class RmtDriver {
|
||||
public:
|
||||
RmtDriver(const LedType& timing, int count, int pin, int channel_num, SemaphoreHandle_t finishedFlag);
|
||||
RmtDriver(const RmtDriver&) = delete;
|
||||
|
||||
esp_err_t init();
|
||||
esp_err_t registerIsr(bool isFirstRegisteredChannel);
|
||||
esp_err_t unregisterIsr();
|
||||
esp_err_t transmit(const Rgb* buffer);
|
||||
|
||||
private:
|
||||
static void IRAM_ATTR txEndCallback(rmt_channel_t channel, void* arg);
|
||||
|
||||
static void IRAM_ATTR translateSample(const void* src, rmt_item32_t* dest, size_t src_size,
|
||||
size_t wanted_rmt_items_num, size_t* out_consumed_src_bytes, size_t* out_used_rmt_items);
|
||||
|
||||
const LedType& _timing;
|
||||
int _count;
|
||||
gpio_num_t _pin;
|
||||
SemaphoreHandle_t _finishedFlag;
|
||||
|
||||
rmt_channel_t _channel;
|
||||
rmt_item32_t _bitToRmt[2];
|
||||
size_t _translatorSourceOffset;
|
||||
};
|
||||
|
||||
};
|
||||
#endif // !SMARTLEDS_NEW_RMT_DRIVER
|
||||
202
code/components/jomjol_controlGPIO/RmtDriver5.cpp
Normal file
202
code/components/jomjol_controlGPIO/RmtDriver5.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/********************************************************************************
|
||||
* https://github.com/RoboticsBrno/SmartLeds
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 RoboticsBrno (RobotikaBrno)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation 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
|
||||
* furnished 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 FOR 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 "RmtDriver5.h"
|
||||
|
||||
#if SMARTLEDS_NEW_RMT_DRIVER
|
||||
#include <cstddef>
|
||||
|
||||
#include "SmartLeds.h"
|
||||
|
||||
namespace detail {
|
||||
|
||||
static constexpr const uint32_t RMT_RESOLUTION_HZ = 20 * 1000 * 1000; // 20 MHz
|
||||
static constexpr const uint32_t RMT_NS_PER_TICK = 1000000000LLU / RMT_RESOLUTION_HZ;
|
||||
|
||||
static RmtEncoderWrapper* IRAM_ATTR encSelf(rmt_encoder_t* encoder) {
|
||||
return (RmtEncoderWrapper*)(((intptr_t)encoder) - offsetof(RmtEncoderWrapper, base));
|
||||
}
|
||||
|
||||
static size_t IRAM_ATTR encEncode(rmt_encoder_t* encoder, rmt_channel_handle_t tx_channel, const void* primary_data,
|
||||
size_t data_size, rmt_encode_state_t* ret_state) {
|
||||
auto* self = encSelf(encoder);
|
||||
|
||||
// Delay after last pixel
|
||||
if ((self->last_state & RMT_ENCODING_COMPLETE) && self->frame_idx == data_size) {
|
||||
*ret_state = (rmt_encode_state_t)0;
|
||||
return self->copy_encoder->encode(
|
||||
self->copy_encoder, tx_channel, (const void*)&self->reset_code, sizeof(self->reset_code), ret_state);
|
||||
}
|
||||
|
||||
if (self->last_state & RMT_ENCODING_COMPLETE) {
|
||||
Rgb* pixel = ((Rgb*)primary_data) + self->frame_idx;
|
||||
self->buffer_len = sizeof(self->buffer);
|
||||
for (size_t i = 0; i < sizeof(self->buffer); ++i) {
|
||||
self->buffer[i] = pixel->getGrb(self->component_idx);
|
||||
if (++self->component_idx == 3) {
|
||||
self->component_idx = 0;
|
||||
if (++self->frame_idx == data_size) {
|
||||
self->buffer_len = i + 1;
|
||||
break;
|
||||
}
|
||||
++pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self->last_state = (rmt_encode_state_t)0;
|
||||
auto encoded_symbols = self->bytes_encoder->encode(
|
||||
self->bytes_encoder, tx_channel, (const void*)&self->buffer, self->buffer_len, &self->last_state);
|
||||
if (self->last_state & RMT_ENCODING_MEM_FULL) {
|
||||
*ret_state = RMT_ENCODING_MEM_FULL;
|
||||
} else {
|
||||
*ret_state = (rmt_encode_state_t)0;
|
||||
}
|
||||
|
||||
return encoded_symbols;
|
||||
}
|
||||
|
||||
static esp_err_t encReset(rmt_encoder_t* encoder) {
|
||||
auto* self = encSelf(encoder);
|
||||
rmt_encoder_reset(self->bytes_encoder);
|
||||
rmt_encoder_reset(self->copy_encoder);
|
||||
self->last_state = RMT_ENCODING_COMPLETE;
|
||||
self->frame_idx = 0;
|
||||
self->component_idx = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t encDelete(rmt_encoder_t* encoder) {
|
||||
auto* self = encSelf(encoder);
|
||||
rmt_del_encoder(self->bytes_encoder);
|
||||
rmt_del_encoder(self->copy_encoder);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
RmtDriver::RmtDriver(const LedType& timing, int count, int pin, int channel_num, SemaphoreHandle_t finishedFlag)
|
||||
: _timing(timing)
|
||||
, _count(count)
|
||||
, _pin(pin)
|
||||
, _finishedFlag(finishedFlag)
|
||||
, _channel(nullptr)
|
||||
, _encoder {} {}
|
||||
|
||||
esp_err_t RmtDriver::init() {
|
||||
_encoder.base.encode = encEncode;
|
||||
_encoder.base.reset = encReset;
|
||||
_encoder.base.del = encDelete;
|
||||
|
||||
_encoder.reset_code.duration0 = _timing.TRS / RMT_NS_PER_TICK;
|
||||
|
||||
rmt_bytes_encoder_config_t bytes_cfg = {
|
||||
.bit0 = {
|
||||
.duration0 = uint16_t(_timing.T0H / RMT_NS_PER_TICK),
|
||||
.level0 = 1,
|
||||
.duration1 = uint16_t(_timing.T0L / RMT_NS_PER_TICK),
|
||||
.level1 = 0,
|
||||
},
|
||||
.bit1 = {
|
||||
.duration0 = uint16_t(_timing.T1H / RMT_NS_PER_TICK),
|
||||
.level0 = 1,
|
||||
.duration1 = uint16_t(_timing.T1L / RMT_NS_PER_TICK),
|
||||
.level1 = 0,
|
||||
},
|
||||
.flags = {
|
||||
.msb_first = 1,
|
||||
},
|
||||
};
|
||||
|
||||
auto err = rmt_new_bytes_encoder(&bytes_cfg, &_encoder.bytes_encoder);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
rmt_copy_encoder_config_t copy_cfg = {};
|
||||
err = rmt_new_copy_encoder(©_cfg, &_encoder.copy_encoder);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// The config must be in registerIsr, because rmt_new_tx_channel
|
||||
// registers the ISR
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t RmtDriver::registerIsr(bool isFirstRegisteredChannel) {
|
||||
rmt_tx_channel_config_t conf = {
|
||||
.gpio_num = (gpio_num_t)_pin,
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT, //.clk_src = RMT_CLK_SRC_APB,
|
||||
.resolution_hz = RMT_RESOLUTION_HZ,
|
||||
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
|
||||
.trans_queue_depth = 1,
|
||||
.flags = {},
|
||||
};
|
||||
|
||||
auto err = rmt_new_tx_channel(&conf, &_channel);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
rmt_tx_event_callbacks_t callbacks_cfg = {};
|
||||
callbacks_cfg.on_trans_done = txDoneCallback;
|
||||
|
||||
err = rmt_tx_register_event_callbacks(_channel, &callbacks_cfg, this);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return rmt_enable(_channel);
|
||||
}
|
||||
|
||||
esp_err_t RmtDriver::unregisterIsr() {
|
||||
auto err = rmt_del_encoder(&_encoder.base);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = rmt_disable(_channel);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return rmt_del_channel(_channel);
|
||||
}
|
||||
|
||||
bool IRAM_ATTR RmtDriver::txDoneCallback(
|
||||
rmt_channel_handle_t tx_chan, const rmt_tx_done_event_data_t* edata, void* user_ctx) {
|
||||
auto* self = (RmtDriver*)user_ctx;
|
||||
auto taskWoken = pdTRUE;
|
||||
xSemaphoreGiveFromISR(self->_finishedFlag, &taskWoken);
|
||||
return taskWoken == pdTRUE;
|
||||
}
|
||||
|
||||
esp_err_t RmtDriver::transmit(const Rgb* buffer) {
|
||||
rmt_encoder_reset(&_encoder.base);
|
||||
rmt_transmit_config_t cfg = {};
|
||||
return rmt_transmit(_channel, &_encoder.base, buffer, _count, &cfg);
|
||||
}
|
||||
};
|
||||
#endif // !SMARTLEDS_NEW_RMT_DRIVER
|
||||
91
code/components/jomjol_controlGPIO/RmtDriver5.h
Normal file
91
code/components/jomjol_controlGPIO/RmtDriver5.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/********************************************************************************
|
||||
* https://github.com/RoboticsBrno/SmartLeds
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 RoboticsBrno (RobotikaBrno)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation 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
|
||||
* furnished 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 FOR 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.
|
||||
*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RmtDriver.h"
|
||||
|
||||
#if SMARTLEDS_NEW_RMT_DRIVER
|
||||
#include <driver/rmt_tx.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <type_traits>
|
||||
|
||||
#include "Color.h"
|
||||
|
||||
#if !defined(CONFIG_RMT_ISR_IRAM_SAFE) && !defined(SMARTLEDS_DISABLE_IRAM_WARNING)
|
||||
#warning "Please enable CONFIG_RMT_ISR_IRAM_SAFE IDF option." \
|
||||
"without it, the IDF driver is not able to supply data fast enough."
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr const int CHANNEL_COUNT = SOC_RMT_GROUPS * SOC_RMT_CHANNELS_PER_GROUP;
|
||||
|
||||
class RmtDriver;
|
||||
|
||||
// This is ridiculous
|
||||
struct RmtEncoderWrapper {
|
||||
struct rmt_encoder_t base;
|
||||
struct rmt_encoder_t* bytes_encoder;
|
||||
struct rmt_encoder_t* copy_encoder;
|
||||
RmtDriver* driver;
|
||||
rmt_symbol_word_t reset_code;
|
||||
|
||||
uint8_t buffer[SOC_RMT_MEM_WORDS_PER_CHANNEL / 8];
|
||||
rmt_encode_state_t last_state;
|
||||
size_t frame_idx;
|
||||
uint8_t component_idx;
|
||||
uint8_t buffer_len;
|
||||
};
|
||||
|
||||
static_assert(std::is_standard_layout<RmtEncoderWrapper>::value == true);
|
||||
|
||||
class RmtDriver {
|
||||
public:
|
||||
RmtDriver(const LedType& timing, int count, int pin, int channel_num, SemaphoreHandle_t finishedFlag);
|
||||
RmtDriver(const RmtDriver&) = delete;
|
||||
|
||||
esp_err_t init();
|
||||
esp_err_t registerIsr(bool isFirstRegisteredChannel);
|
||||
esp_err_t unregisterIsr();
|
||||
esp_err_t transmit(const Rgb* buffer);
|
||||
|
||||
private:
|
||||
static bool IRAM_ATTR txDoneCallback(
|
||||
rmt_channel_handle_t tx_chan, const rmt_tx_done_event_data_t* edata, void* user_ctx);
|
||||
|
||||
const LedType& _timing;
|
||||
int _count;
|
||||
int _pin;
|
||||
SemaphoreHandle_t _finishedFlag;
|
||||
|
||||
rmt_channel_handle_t _channel;
|
||||
RmtEncoderWrapper _encoder;
|
||||
};
|
||||
|
||||
};
|
||||
#endif // !SMARTLEDS_NEW_RMT_DRIVER
|
||||
@@ -1,90 +1,35 @@
|
||||
/********************************************************************************
|
||||
* https://github.com/RoboticsBrno/SmartLeds
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 RoboticsBrno (RobotikaBrno)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation 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
|
||||
* furnished 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 FOR 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 "SmartLeds.h"
|
||||
|
||||
|
||||
/* PlatformIO 6 (ESP IDF 5) does no longer allow access to RMTMEM,
|
||||
see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/migration-guides/release-5.x/5.0/peripherals.html?highlight=rmtmem#id5
|
||||
As a dirty workaround, we copy the needed structures from rmt_struct.h
|
||||
In the long run, this should be replaced! */
|
||||
typedef struct rmt_item32_s {
|
||||
union {
|
||||
struct {
|
||||
uint32_t duration0 :15;
|
||||
uint32_t level0 :1;
|
||||
uint32_t duration1 :15;
|
||||
uint32_t level1 :1;
|
||||
};
|
||||
uint32_t val;
|
||||
};
|
||||
} rmt_item32_t;
|
||||
|
||||
//Allow access to RMT memory using RMTMEM.chan[0].data32[8]
|
||||
typedef volatile struct rmt_mem_s {
|
||||
struct {
|
||||
rmt_item32_t data32[64];
|
||||
} chan[8];
|
||||
} rmt_mem_t;
|
||||
extern rmt_mem_t RMTMEM;
|
||||
|
||||
|
||||
|
||||
IsrCore SmartLed::_interruptCore = CoreCurrent;
|
||||
intr_handle_t SmartLed::_interruptHandle = NULL;
|
||||
|
||||
SmartLed*& IRAM_ATTR SmartLed::ledForChannel( int channel ) {
|
||||
static SmartLed* table[8] = { nullptr };
|
||||
assert( channel < 8 );
|
||||
return table[ channel ];
|
||||
}
|
||||
|
||||
void IRAM_ATTR SmartLed::interruptHandler(void*) {
|
||||
for (int channel = 0; channel != 8; channel++) {
|
||||
auto self = ledForChannel( channel );
|
||||
|
||||
if ( RMT.int_st.val & (1 << (24 + channel ) ) ) { // tx_thr_event
|
||||
if ( self )
|
||||
self->copyRmtHalfBlock();
|
||||
RMT.int_clr.val |= 1 << ( 24 + channel );
|
||||
} else if ( RMT.int_st.val & ( 1 << (3 * channel ) ) ) { // tx_end
|
||||
if ( self )
|
||||
xSemaphoreGiveFromISR( self->_finishedFlag, nullptr );
|
||||
RMT.int_clr.val |= 1 << ( 3 * channel );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR SmartLed::copyRmtHalfBlock() {
|
||||
int offset = detail::MAX_PULSES * _halfIdx;
|
||||
_halfIdx = !_halfIdx;
|
||||
int len = 3 - _componentPosition + 3 * ( _count - 1 );
|
||||
len = std::min( len, detail::MAX_PULSES / 8 );
|
||||
|
||||
if ( !len ) {
|
||||
for ( int i = 0; i < detail::MAX_PULSES; i++) {
|
||||
RMTMEM.chan[ _channel].data32[i + offset ].val = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int i;
|
||||
for ( i = 0; i != len && _pixelPosition != _count; i++ ) {
|
||||
uint8_t val = _buffer[ _pixelPosition ].getGrb( _componentPosition );
|
||||
for ( int j = 0; j != 8; j++, val <<= 1 ) {
|
||||
int bit = val >> 7;
|
||||
int idx = i * 8 + offset + j;
|
||||
RMTMEM.chan[ _channel ].data32[ idx ].val = _bitToRmt[ bit & 0x01 ].value;
|
||||
}
|
||||
if ( _pixelPosition == _count - 1 && _componentPosition == 2 ) {
|
||||
RMTMEM.chan[ _channel ].data32[ i * 8 + offset + 7 ].duration1 =
|
||||
_timing.TRS / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
}
|
||||
|
||||
_componentPosition++;
|
||||
if ( _componentPosition == 3 ) {
|
||||
_componentPosition = 0;
|
||||
_pixelPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
for ( i *= 8; i != detail::MAX_PULSES; i++ ) {
|
||||
RMTMEM.chan[ _channel ].data32[ i + offset ].val = 0;
|
||||
}
|
||||
SmartLed*& IRAM_ATTR SmartLed::ledForChannel(int channel) {
|
||||
static SmartLed* table[detail::CHANNEL_COUNT] = {};
|
||||
assert(channel < detail::CHANNEL_COUNT);
|
||||
return table[channel];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,30 @@
|
||||
#pragma once
|
||||
/********************************************************************************
|
||||
* https://github.com/RoboticsBrno/SmartLeds
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 RoboticsBrno (RobotikaBrno)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation 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
|
||||
* furnished 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 FOR 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 SMARTLEDS_H
|
||||
#define SMARTLEDS_H
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* A C++ driver for the WS2812 LEDs using the RMT peripheral on the ESP32.
|
||||
@@ -31,305 +54,196 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "esp_idf_version.h"
|
||||
#if (ESP_IDF_VERSION_MAJOR >= 5)
|
||||
#include "soc/periph_defs.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#define gpio_pad_select_gpio esp_rom_gpio_pad_select_gpio
|
||||
#define gpio_matrix_in(a,b,c) esp_rom_gpio_connect_in_signal(a,b,c)
|
||||
#define gpio_matrix_out(a,b,c,d) esp_rom_gpio_connect_out_signal(a,b,c,d)
|
||||
#define ets_delay_us(a) esp_rom_delay_us(a)
|
||||
#endif
|
||||
|
||||
#if defined ( ARDUINO )
|
||||
extern "C" { // ...someone forgot to put in the includes...
|
||||
#include "esp32-hal.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_ipc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "soc/rmt_struct.h"
|
||||
#include <driver/spi_master.h>
|
||||
#include "esp_idf_version.h"
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
|
||||
#include "soc/dport_reg.h"
|
||||
#endif
|
||||
}
|
||||
#elif defined ( ESP_PLATFORM )
|
||||
extern "C" { // ...someone forgot to put in the includes...
|
||||
#include <esp_intr_alloc.h>
|
||||
#include <esp_ipc.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <soc/dport_reg.h>
|
||||
#include <soc/gpio_sig_map.h>
|
||||
#include <soc/rmt_struct.h>
|
||||
#include <driver/spi_master.h>
|
||||
}
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR >= 4) && (ESP_IDF_VERSION_MINOR > 1)
|
||||
#include "hal/gpio_ll.h"
|
||||
#else
|
||||
#include "soc/gpio_periph.h"
|
||||
#define esp_rom_delay_us ets_delay_us
|
||||
static inline int gpio_ll_get_level(gpio_dev_t *hw, int gpio_num)
|
||||
{
|
||||
if (gpio_num < 32) {
|
||||
return (hw->in >> gpio_num) & 0x1;
|
||||
} else {
|
||||
return (hw->in1.data >> (gpio_num - 32)) & 0x1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0))
|
||||
#if !(configENABLE_BACKWARD_COMPATIBILITY == 1)
|
||||
#define xSemaphoreHandle SemaphoreHandle_t
|
||||
#endif
|
||||
#endif
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include <esp_intr_alloc.h>
|
||||
#include <esp_ipc.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
#include "Color.h"
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct TimingParams {
|
||||
uint32_t T0H;
|
||||
uint32_t T1H;
|
||||
uint32_t T0L;
|
||||
uint32_t T1L;
|
||||
uint32_t TRS;
|
||||
};
|
||||
|
||||
union RmtPulsePair {
|
||||
struct {
|
||||
int duration0:15;
|
||||
int level0:1;
|
||||
int duration1:15;
|
||||
int level1:1;
|
||||
};
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
static const int DIVIDER = 4; // 8 still seems to work, but timings become marginal
|
||||
static const int MAX_PULSES = 32; // A channel has a 64 "pulse" buffer - we use half per pass
|
||||
static const double RMT_DURATION_NS = 12.5; // minimum time of a single RMT duration based on clock ns
|
||||
|
||||
} // namespace detail
|
||||
#include "RmtDriver.h"
|
||||
|
||||
using LedType = detail::TimingParams;
|
||||
|
||||
static const LedType LED_WS2812 = { 350, 700, 800, 600, 50000 };
|
||||
static const LedType LED_WS2812B = { 400, 850, 850, 400, 50100 };
|
||||
static const LedType LED_SK6812 = { 300, 600, 900, 600, 80000 };
|
||||
static const LedType LED_WS2813 = { 350, 800, 350, 350, 300000 };
|
||||
// Times are in nanoseconds,
|
||||
// The RMT driver runs at 20MHz, so minimal representable time is 50 nanoseconds
|
||||
static const LedType LED_WS2812 = { 350, 700, 800, 600, 50000 };
|
||||
// longer reset time because https://blog.adafruit.com/2017/05/03/psa-the-ws2812b-rgb-led-has-been-revised-will-require-code-tweak/
|
||||
static const LedType LED_WS2812B = { 400, 800, 850, 450, 300000 }; // universal
|
||||
static const LedType LED_WS2812B_NEWVARIANT = { 200, 750, 750, 200, 300000 };
|
||||
static const LedType LED_WS2812B_OLDVARIANT = { 400, 800, 850, 450, 50000 };
|
||||
// This is timing from datasheet, but does not seem to actually work - try LED_WS2812B
|
||||
static const LedType LED_WS2812C = { 250, 550, 550, 250, 280000 };
|
||||
static const LedType LED_SK6812 = { 300, 600, 900, 600, 80000 };
|
||||
static const LedType LED_WS2813 = { 350, 800, 350, 350, 300000 };
|
||||
|
||||
// Single buffer == can't touch the Rgbs between show() and wait()
|
||||
enum BufferType { SingleBuffer = 0, DoubleBuffer };
|
||||
|
||||
enum IsrCore { CoreFirst = 0, CoreSecond = 1, CoreCurrent = 2};
|
||||
enum IsrCore { CoreFirst = 0, CoreSecond = 1, CoreCurrent = 2 };
|
||||
|
||||
class SmartLed {
|
||||
public:
|
||||
friend class detail::RmtDriver;
|
||||
|
||||
// The RMT interrupt must not run on the same core as WiFi interrupts, otherwise SmartLeds
|
||||
// can't fill the RMT buffer fast enough, resulting in rendering artifacts.
|
||||
// Usually, that means you have to set isrCore == CoreSecond.
|
||||
//
|
||||
// If you use anything other than CoreCurrent, the FreeRTOS scheduler MUST be already running,
|
||||
// so you can't use it if you define SmartLed as global variable.
|
||||
SmartLed( const LedType& type, int count, int pin, int channel = 0, BufferType doubleBuffer = SingleBuffer, IsrCore isrCore = CoreCurrent)
|
||||
: _timing( type ),
|
||||
_channel( channel ),
|
||||
_count( count ),
|
||||
_firstBuffer( new Rgb[ count ] ),
|
||||
_secondBuffer( doubleBuffer ? new Rgb[ count ] : nullptr ),
|
||||
_finishedFlag( xSemaphoreCreateBinary() )
|
||||
{
|
||||
assert( channel >= 0 && channel < 8 );
|
||||
assert( ledForChannel( channel ) == nullptr );
|
||||
//
|
||||
// Does nothing on chips that only have one core.
|
||||
SmartLed(const LedType& type, int count, int pin, int channel = 0, BufferType doubleBuffer = DoubleBuffer,
|
||||
IsrCore isrCore = CoreCurrent)
|
||||
: _finishedFlag(xSemaphoreCreateBinary())
|
||||
, _driver(type, count, pin, channel, _finishedFlag)
|
||||
, _channel(channel)
|
||||
, _count(count)
|
||||
, _firstBuffer(new Rgb[count])
|
||||
, _secondBuffer(doubleBuffer ? new Rgb[count] : nullptr) {
|
||||
assert(channel >= 0 && channel < detail::CHANNEL_COUNT);
|
||||
assert(ledForChannel(channel) == nullptr);
|
||||
|
||||
xSemaphoreGive( _finishedFlag );
|
||||
xSemaphoreGive(_finishedFlag);
|
||||
|
||||
DPORT_SET_PERI_REG_MASK( DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN );
|
||||
DPORT_CLEAR_PERI_REG_MASK( DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST );
|
||||
_driver.init();
|
||||
|
||||
PIN_FUNC_SELECT( GPIO_PIN_MUX_REG[ pin ], 2 );
|
||||
gpio_set_direction( static_cast< gpio_num_t >( pin ), GPIO_MODE_OUTPUT );
|
||||
gpio_matrix_out( static_cast< gpio_num_t >( pin ), RMT_SIG_OUT0_IDX + _channel, 0, 0 );
|
||||
initChannel( _channel );
|
||||
|
||||
RMT.tx_lim_ch[ _channel ].limit = detail::MAX_PULSES;
|
||||
RMT.int_ena.val |= 1 << ( 24 + _channel );
|
||||
RMT.int_ena.val |= 1 << ( 3 * _channel );
|
||||
|
||||
_bitToRmt[ 0 ].level0 = 1;
|
||||
_bitToRmt[ 0 ].level1 = 0;
|
||||
_bitToRmt[ 0 ].duration0 = _timing.T0H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
_bitToRmt[ 0 ].duration1 = _timing.T0L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
|
||||
_bitToRmt[ 1 ].level0 = 1;
|
||||
_bitToRmt[ 1 ].level1 = 0;
|
||||
_bitToRmt[ 1 ].duration0 = _timing.T1H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
_bitToRmt[ 1 ].duration1 = _timing.T1L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
|
||||
if ( !anyAlive() ) {
|
||||
#if !defined(SOC_CPU_CORES_NUM) || SOC_CPU_CORES_NUM > 1
|
||||
if (!anyAlive() && isrCore != CoreCurrent) {
|
||||
_interruptCore = isrCore;
|
||||
if(isrCore != CoreCurrent) {
|
||||
ESP_ERROR_CHECK(esp_ipc_call_blocking(isrCore, registerInterrupt, NULL));
|
||||
} else {
|
||||
registerInterrupt(NULL);
|
||||
}
|
||||
ESP_ERROR_CHECK(esp_ipc_call_blocking(isrCore, registerInterrupt, (void*)this));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
registerInterrupt((void*)this);
|
||||
}
|
||||
|
||||
ledForChannel( channel ) = this;
|
||||
ledForChannel(channel) = this;
|
||||
}
|
||||
|
||||
~SmartLed() {
|
||||
ledForChannel( _channel ) = nullptr;
|
||||
if ( !anyAlive() ) {
|
||||
if(_interruptCore != CoreCurrent) {
|
||||
ESP_ERROR_CHECK(esp_ipc_call_blocking(_interruptCore, unregisterInterrupt, NULL));
|
||||
} else {
|
||||
unregisterInterrupt(NULL);
|
||||
}
|
||||
ledForChannel(_channel) = nullptr;
|
||||
#if !defined(SOC_CPU_CORES_NUM) || SOC_CPU_CORES_NUM > 1
|
||||
if (!anyAlive() && _interruptCore != CoreCurrent) {
|
||||
ESP_ERROR_CHECK(esp_ipc_call_blocking(_interruptCore, unregisterInterrupt, (void*)this));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
unregisterInterrupt((void*)this);
|
||||
}
|
||||
vSemaphoreDelete( _finishedFlag );
|
||||
vSemaphoreDelete(_finishedFlag);
|
||||
}
|
||||
|
||||
Rgb& operator[]( int idx ) {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
Rgb& operator[](int idx) { return _firstBuffer[idx]; }
|
||||
|
||||
const Rgb& operator[]( int idx ) const {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
const Rgb& operator[](int idx) const { return _firstBuffer[idx]; }
|
||||
|
||||
void show() {
|
||||
_buffer = _firstBuffer.get();
|
||||
startTransmission();
|
||||
esp_err_t show() {
|
||||
esp_err_t err = startTransmission();
|
||||
swapBuffers();
|
||||
return err;
|
||||
}
|
||||
|
||||
bool wait( TickType_t timeout = portMAX_DELAY ) {
|
||||
if( xSemaphoreTake( _finishedFlag, timeout ) == pdTRUE ) {
|
||||
xSemaphoreGive( _finishedFlag );
|
||||
bool wait(TickType_t timeout = portMAX_DELAY) {
|
||||
if (xSemaphoreTake(_finishedFlag, timeout) == pdTRUE) {
|
||||
xSemaphoreGive(_finishedFlag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int size() const {
|
||||
return _count;
|
||||
}
|
||||
int size() const { return _count; }
|
||||
int channel() const { return _channel; }
|
||||
|
||||
Rgb *begin() { return _firstBuffer.get(); }
|
||||
const Rgb *begin() const { return _firstBuffer.get(); }
|
||||
const Rgb *cbegin() const { return _firstBuffer.get(); }
|
||||
Rgb* begin() { return _firstBuffer.get(); }
|
||||
const Rgb* begin() const { return _firstBuffer.get(); }
|
||||
const Rgb* cbegin() const { return _firstBuffer.get(); }
|
||||
|
||||
Rgb *end() { return _firstBuffer.get() + _count; }
|
||||
const Rgb *end() const { return _firstBuffer.get() + _count; }
|
||||
const Rgb *cend() const { return _firstBuffer.get() + _count; }
|
||||
Rgb* end() { return _firstBuffer.get() + _count; }
|
||||
const Rgb* end() const { return _firstBuffer.get() + _count; }
|
||||
const Rgb* cend() const { return _firstBuffer.get() + _count; }
|
||||
|
||||
private:
|
||||
static intr_handle_t _interruptHandle;
|
||||
static IsrCore _interruptCore;
|
||||
|
||||
static void initChannel( int channel ) {
|
||||
RMT.apb_conf.fifo_mask = 1; //enable memory access, instead of FIFO mode.
|
||||
RMT.apb_conf.mem_tx_wrap_en = 1; //wrap around when hitting end of buffer
|
||||
RMT.conf_ch[ channel ].conf0.div_cnt = detail::DIVIDER;
|
||||
RMT.conf_ch[ channel ].conf0.mem_size = 1;
|
||||
RMT.conf_ch[ channel ].conf0.carrier_en = 0;
|
||||
RMT.conf_ch[ channel ].conf0.carrier_out_lv = 1;
|
||||
RMT.conf_ch[ channel ].conf0.mem_pd = 0;
|
||||
|
||||
RMT.conf_ch[ channel ].conf1.rx_en = 0;
|
||||
RMT.conf_ch[ channel ].conf1.mem_owner = 0;
|
||||
RMT.conf_ch[ channel ].conf1.tx_conti_mode = 0; //loop back mode.
|
||||
RMT.conf_ch[ channel ].conf1.ref_always_on = 1; // use apb clock: 80M
|
||||
RMT.conf_ch[ channel ].conf1.idle_out_en = 1;
|
||||
RMT.conf_ch[ channel ].conf1.idle_out_lv = 0;
|
||||
static void registerInterrupt(void* selfVoid) {
|
||||
auto* self = (SmartLed*)selfVoid;
|
||||
ESP_ERROR_CHECK(self->_driver.registerIsr(!anyAlive()));
|
||||
}
|
||||
|
||||
static void registerInterrupt(void *) {
|
||||
ESP_ERROR_CHECK(esp_intr_alloc( ETS_RMT_INTR_SOURCE, 0, interruptHandler, nullptr, &_interruptHandle));
|
||||
static void unregisterInterrupt(void* selfVoid) {
|
||||
auto* self = (SmartLed*)selfVoid;
|
||||
ESP_ERROR_CHECK(self->_driver.unregisterIsr());
|
||||
}
|
||||
|
||||
static void unregisterInterrupt(void*) {
|
||||
esp_intr_free( _interruptHandle );
|
||||
}
|
||||
|
||||
static SmartLed*& IRAM_ATTR ledForChannel( int channel );
|
||||
static void IRAM_ATTR interruptHandler( void* );
|
||||
|
||||
void IRAM_ATTR copyRmtHalfBlock();
|
||||
|
||||
void swapBuffers() {
|
||||
if ( _secondBuffer )
|
||||
_firstBuffer.swap( _secondBuffer );
|
||||
}
|
||||
|
||||
void startTransmission() {
|
||||
// Invalid use of the library
|
||||
if( xSemaphoreTake( _finishedFlag, 0 ) != pdTRUE )
|
||||
abort();
|
||||
|
||||
_pixelPosition = _componentPosition = _halfIdx = 0;
|
||||
copyRmtHalfBlock();
|
||||
if ( _pixelPosition < _count )
|
||||
copyRmtHalfBlock();
|
||||
|
||||
RMT.conf_ch[ _channel ].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[ _channel ].conf1.tx_start = 1;
|
||||
}
|
||||
static SmartLed*& IRAM_ATTR ledForChannel(int channel);
|
||||
|
||||
static bool anyAlive() {
|
||||
for ( int i = 0; i != 8; i++ )
|
||||
if ( ledForChannel( i ) != nullptr ) return true;
|
||||
for (int i = 0; i != detail::CHANNEL_COUNT; i++)
|
||||
if (ledForChannel(i) != nullptr)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const LedType& _timing;
|
||||
void swapBuffers() {
|
||||
if (_secondBuffer)
|
||||
_firstBuffer.swap(_secondBuffer);
|
||||
}
|
||||
|
||||
esp_err_t startTransmission() {
|
||||
// Invalid use of the library, you must wait() fir previous frame to get processed first
|
||||
if (xSemaphoreTake(_finishedFlag, 0) != pdTRUE)
|
||||
abort();
|
||||
|
||||
auto err = _driver.transmit(_firstBuffer.get());
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
SemaphoreHandle_t _finishedFlag;
|
||||
detail::RmtDriver _driver;
|
||||
int _channel;
|
||||
detail::RmtPulsePair _bitToRmt[ 2 ];
|
||||
int _count;
|
||||
std::unique_ptr< Rgb[] > _firstBuffer;
|
||||
std::unique_ptr< Rgb[] > _secondBuffer;
|
||||
Rgb *_buffer;
|
||||
|
||||
xSemaphoreHandle _finishedFlag;
|
||||
|
||||
int _pixelPosition;
|
||||
int _componentPosition;
|
||||
int _halfIdx;
|
||||
std::unique_ptr<Rgb[]> _firstBuffer;
|
||||
std::unique_ptr<Rgb[]> _secondBuffer;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#define _SMARTLEDS_SPI_HOST SPI2_HOST
|
||||
#define _SMARTLEDS_SPI_DMA_CHAN SPI_DMA_CH_AUTO
|
||||
#else
|
||||
#define _SMARTLEDS_SPI_HOST HSPI_HOST
|
||||
#define _SMARTLEDS_SPI_DMA_CHAN 1
|
||||
#endif
|
||||
|
||||
class Apa102 {
|
||||
public:
|
||||
struct ApaRgb {
|
||||
ApaRgb( uint8_t r = 0, uint8_t g = 0, uint32_t b = 0, uint32_t v = 0xFF )
|
||||
: v( 0xE0 | v ), b( b ), g( g ), r( r )
|
||||
{}
|
||||
ApaRgb(uint8_t r = 0, uint8_t g = 0, uint32_t b = 0, uint32_t v = 0xFF)
|
||||
: v(0xE0 | v)
|
||||
, b(b)
|
||||
, g(g)
|
||||
, r(r) {}
|
||||
|
||||
ApaRgb& operator=( const Rgb& o ) {
|
||||
ApaRgb& operator=(const Rgb& o) {
|
||||
r = o.r;
|
||||
g = o.g;
|
||||
b = o.b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ApaRgb& operator=( const Hsv& o ) {
|
||||
*this = Rgb{ o };
|
||||
ApaRgb& operator=(const Hsv& o) {
|
||||
*this = Rgb { o };
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -339,14 +253,14 @@ public:
|
||||
static const int FINAL_FRAME_SIZE = 4;
|
||||
static const int TRANS_COUNT = 2 + 8;
|
||||
|
||||
Apa102( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer )
|
||||
: _count( count ),
|
||||
_firstBuffer( new ApaRgb[ count ] ),
|
||||
_secondBuffer( doubleBuffer ? new ApaRgb[ count ] : nullptr ),
|
||||
_initFrame( 0 )
|
||||
{
|
||||
Apa102(int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer, int clock_speed_hz = 1000000)
|
||||
: _count(count)
|
||||
, _firstBuffer(new ApaRgb[count])
|
||||
, _secondBuffer(doubleBuffer ? new ApaRgb[count] : nullptr)
|
||||
, _transCount(0)
|
||||
, _initFrame(0) {
|
||||
spi_bus_config_t buscfg;
|
||||
memset( &buscfg, 0, sizeof( buscfg ) );
|
||||
memset(&buscfg, 0, sizeof(buscfg));
|
||||
buscfg.mosi_io_num = datapin;
|
||||
buscfg.miso_io_num = -1;
|
||||
buscfg.sclk_io_num = clkpin;
|
||||
@@ -355,33 +269,29 @@ public:
|
||||
buscfg.max_transfer_sz = 65535;
|
||||
|
||||
spi_device_interface_config_t devcfg;
|
||||
memset( &devcfg, 0, sizeof( devcfg ) );
|
||||
devcfg.clock_speed_hz = 1000000;
|
||||
memset(&devcfg, 0, sizeof(devcfg));
|
||||
devcfg.clock_speed_hz = clock_speed_hz;
|
||||
devcfg.mode = 0;
|
||||
devcfg.spics_io_num = -1;
|
||||
devcfg.queue_size = TRANS_COUNT;
|
||||
devcfg.pre_cb = nullptr;
|
||||
|
||||
auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
|
||||
assert( ret == ESP_OK );
|
||||
auto ret = spi_bus_initialize(_SMARTLEDS_SPI_HOST, &buscfg, _SMARTLEDS_SPI_DMA_CHAN);
|
||||
assert(ret == ESP_OK);
|
||||
|
||||
ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
|
||||
assert( ret == ESP_OK );
|
||||
ret = spi_bus_add_device(_SMARTLEDS_SPI_HOST, &devcfg, &_spi);
|
||||
assert(ret == ESP_OK);
|
||||
|
||||
std::fill_n( _finalFrame, FINAL_FRAME_SIZE, 0xFFFFFFFF );
|
||||
std::fill_n(_finalFrame, FINAL_FRAME_SIZE, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
~Apa102() {
|
||||
// ToDo
|
||||
}
|
||||
|
||||
ApaRgb& operator[]( int idx ) {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
ApaRgb& operator[](int idx) { return _firstBuffer[idx]; }
|
||||
|
||||
const ApaRgb& operator[]( int idx ) const {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
const ApaRgb& operator[](int idx) const { return _firstBuffer[idx]; }
|
||||
|
||||
void show() {
|
||||
_buffer = _firstBuffer.get();
|
||||
@@ -390,93 +300,95 @@ public:
|
||||
}
|
||||
|
||||
void wait() {
|
||||
for ( int i = 0; i != _transCount; i++ ) {
|
||||
spi_transaction_t *t;
|
||||
spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
|
||||
for (int i = 0; i != _transCount; i++) {
|
||||
spi_transaction_t* t;
|
||||
spi_device_get_trans_result(_spi, &t, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void swapBuffers() {
|
||||
if ( _secondBuffer )
|
||||
_firstBuffer.swap( _secondBuffer );
|
||||
if (_secondBuffer)
|
||||
_firstBuffer.swap(_secondBuffer);
|
||||
}
|
||||
|
||||
void startTransmission() {
|
||||
for ( int i = 0; i != TRANS_COUNT; i++ ) {
|
||||
_transactions[ i ].cmd = 0;
|
||||
_transactions[ i ].addr = 0;
|
||||
_transactions[ i ].flags = 0;
|
||||
_transactions[ i ].rxlength = 0;
|
||||
_transactions[ i ].rx_buffer = nullptr;
|
||||
for (int i = 0; i != TRANS_COUNT; i++) {
|
||||
_transactions[i].cmd = 0;
|
||||
_transactions[i].addr = 0;
|
||||
_transactions[i].flags = 0;
|
||||
_transactions[i].rxlength = 0;
|
||||
_transactions[i].rx_buffer = nullptr;
|
||||
}
|
||||
// Init frame
|
||||
_transactions[ 0 ].length = 32;
|
||||
_transactions[ 0 ].tx_buffer = &_initFrame;
|
||||
spi_device_queue_trans( _spi, _transactions + 0, portMAX_DELAY );
|
||||
_transactions[0].length = 32;
|
||||
_transactions[0].tx_buffer = &_initFrame;
|
||||
spi_device_queue_trans(_spi, _transactions + 0, portMAX_DELAY);
|
||||
// Data
|
||||
_transactions[ 1 ].length = 32 * _count;
|
||||
_transactions[ 1 ].tx_buffer = _buffer;
|
||||
spi_device_queue_trans( _spi, _transactions + 1, portMAX_DELAY );
|
||||
_transactions[1].length = 32 * _count;
|
||||
_transactions[1].tx_buffer = _buffer;
|
||||
spi_device_queue_trans(_spi, _transactions + 1, portMAX_DELAY);
|
||||
_transCount = 2;
|
||||
// End frame
|
||||
for ( int i = 0; i != 1 + _count / 32 / FINAL_FRAME_SIZE; i++ ) {
|
||||
_transactions[ 2 + i ].length = 32 * FINAL_FRAME_SIZE;
|
||||
_transactions[ 2 + i ].tx_buffer = _finalFrame;
|
||||
spi_device_queue_trans( _spi, _transactions + 2 + i, portMAX_DELAY );
|
||||
for (int i = 0; i != 1 + _count / 32 / FINAL_FRAME_SIZE; i++) {
|
||||
_transactions[2 + i].length = 32 * FINAL_FRAME_SIZE;
|
||||
_transactions[2 + i].tx_buffer = _finalFrame;
|
||||
spi_device_queue_trans(_spi, _transactions + 2 + i, portMAX_DELAY);
|
||||
_transCount++;
|
||||
}
|
||||
}
|
||||
|
||||
spi_device_handle_t _spi;
|
||||
int _count;
|
||||
std::unique_ptr< ApaRgb[] > _firstBuffer, _secondBuffer;
|
||||
ApaRgb *_buffer;
|
||||
std::unique_ptr<ApaRgb[]> _firstBuffer, _secondBuffer;
|
||||
ApaRgb* _buffer;
|
||||
|
||||
spi_transaction_t _transactions[ TRANS_COUNT ];
|
||||
spi_transaction_t _transactions[TRANS_COUNT];
|
||||
int _transCount;
|
||||
|
||||
uint32_t _initFrame;
|
||||
uint32_t _finalFrame[ FINAL_FRAME_SIZE ];
|
||||
uint32_t _finalFrame[FINAL_FRAME_SIZE];
|
||||
};
|
||||
|
||||
class LDP8806 {
|
||||
public:
|
||||
struct LDP8806_GRB {
|
||||
|
||||
LDP8806_GRB( uint8_t g_7bit = 0, uint8_t r_7bit = 0, uint32_t b_7bit = 0 )
|
||||
: g( g_7bit ), r( r_7bit ), b( b_7bit )
|
||||
{
|
||||
}
|
||||
LDP8806_GRB(uint8_t g_7bit = 0, uint8_t r_7bit = 0, uint32_t b_7bit = 0)
|
||||
: g(g_7bit)
|
||||
, r(r_7bit)
|
||||
, b(b_7bit) {}
|
||||
|
||||
LDP8806_GRB& operator=( const Rgb& o ) {
|
||||
LDP8806_GRB& operator=(const Rgb& o) {
|
||||
//Convert 8->7bit colour
|
||||
r = ( o.r * 127 / 256 ) | 0x80;
|
||||
g = ( o.g * 127 / 256 ) | 0x80;
|
||||
b = ( o.b * 127 / 256 ) | 0x80;
|
||||
r = (o.r * 127 / 256) | 0x80;
|
||||
g = (o.g * 127 / 256) | 0x80;
|
||||
b = (o.b * 127 / 256) | 0x80;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LDP8806_GRB& operator=( const Hsv& o ) {
|
||||
*this = Rgb{ o };
|
||||
LDP8806_GRB& operator=(const Hsv& o) {
|
||||
*this = Rgb { o };
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8_t g, r, b;
|
||||
};
|
||||
|
||||
static const int LED_FRAME_SIZE_BYTES = sizeof( LDP8806_GRB );
|
||||
static const int LED_FRAME_SIZE_BYTES = sizeof(LDP8806_GRB);
|
||||
static const int LATCH_FRAME_SIZE_BYTES = 3;
|
||||
static const int TRANS_COUNT_MAX = 20;//Arbitrary, supports up to 600 LED
|
||||
static const int TRANS_COUNT_MAX = 20; //Arbitrary, supports up to 600 LED
|
||||
|
||||
LDP8806( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer, uint32_t clock_speed_hz = 2000000 )
|
||||
: _count( count ),
|
||||
_firstBuffer( new LDP8806_GRB[ count ] ),
|
||||
_secondBuffer( doubleBuffer ? new LDP8806_GRB[ count ] : nullptr ),
|
||||
// one 'latch'/start-of-data mark frame for every 32 leds
|
||||
_latchFrames( ( count + 31 ) / 32 )
|
||||
{
|
||||
LDP8806(
|
||||
int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer, uint32_t clock_speed_hz = 2000000)
|
||||
: _count(count)
|
||||
, _firstBuffer(new LDP8806_GRB[count])
|
||||
, _secondBuffer(doubleBuffer ? new LDP8806_GRB[count] : nullptr)
|
||||
,
|
||||
// one 'latch'/start-of-data mark frame for every 32 leds
|
||||
_latchFrames((count + 31) / 32) {
|
||||
spi_bus_config_t buscfg;
|
||||
memset( &buscfg, 0, sizeof( buscfg ) );
|
||||
memset(&buscfg, 0, sizeof(buscfg));
|
||||
buscfg.mosi_io_num = datapin;
|
||||
buscfg.miso_io_num = -1;
|
||||
buscfg.sclk_io_num = clkpin;
|
||||
@@ -485,33 +397,29 @@ public:
|
||||
buscfg.max_transfer_sz = 65535;
|
||||
|
||||
spi_device_interface_config_t devcfg;
|
||||
memset( &devcfg, 0, sizeof( devcfg ) );
|
||||
memset(&devcfg, 0, sizeof(devcfg));
|
||||
devcfg.clock_speed_hz = clock_speed_hz;
|
||||
devcfg.mode = 0;
|
||||
devcfg.spics_io_num = -1;
|
||||
devcfg.queue_size = TRANS_COUNT_MAX;
|
||||
devcfg.pre_cb = nullptr;
|
||||
|
||||
auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
|
||||
assert( ret == ESP_OK );
|
||||
auto ret = spi_bus_initialize(_SMARTLEDS_SPI_HOST, &buscfg, _SMARTLEDS_SPI_DMA_CHAN);
|
||||
assert(ret == ESP_OK);
|
||||
|
||||
ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
|
||||
assert( ret == ESP_OK );
|
||||
ret = spi_bus_add_device(_SMARTLEDS_SPI_HOST, &devcfg, &_spi);
|
||||
assert(ret == ESP_OK);
|
||||
|
||||
std::fill_n( _latchBuffer, LATCH_FRAME_SIZE_BYTES, 0x0 );
|
||||
std::fill_n(_latchBuffer, LATCH_FRAME_SIZE_BYTES, 0x0);
|
||||
}
|
||||
|
||||
~LDP8806() {
|
||||
// noop
|
||||
}
|
||||
|
||||
LDP8806_GRB& operator[]( int idx ) {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
LDP8806_GRB& operator[](int idx) { return _firstBuffer[idx]; }
|
||||
|
||||
const LDP8806_GRB& operator[]( int idx ) const {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
const LDP8806_GRB& operator[](int idx) const { return _firstBuffer[idx]; }
|
||||
|
||||
void show() {
|
||||
_buffer = _firstBuffer.get();
|
||||
@@ -520,51 +428,50 @@ public:
|
||||
}
|
||||
|
||||
void wait() {
|
||||
while ( _transCount-- ) {
|
||||
spi_transaction_t *t;
|
||||
spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
|
||||
while (_transCount--) {
|
||||
spi_transaction_t* t;
|
||||
spi_device_get_trans_result(_spi, &t, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void swapBuffers() {
|
||||
if ( _secondBuffer )
|
||||
_firstBuffer.swap( _secondBuffer );
|
||||
if (_secondBuffer)
|
||||
_firstBuffer.swap(_secondBuffer);
|
||||
}
|
||||
|
||||
void startTransmission() {
|
||||
_transCount = 0;
|
||||
for ( int i = 0; i != TRANS_COUNT_MAX; i++ ) {
|
||||
_transactions[ i ].cmd = 0;
|
||||
_transactions[ i ].addr = 0;
|
||||
_transactions[ i ].flags = 0;
|
||||
_transactions[ i ].rxlength = 0;
|
||||
_transactions[ i ].rx_buffer = nullptr;
|
||||
for (int i = 0; i != TRANS_COUNT_MAX; i++) {
|
||||
_transactions[i].cmd = 0;
|
||||
_transactions[i].addr = 0;
|
||||
_transactions[i].flags = 0;
|
||||
_transactions[i].rxlength = 0;
|
||||
_transactions[i].rx_buffer = nullptr;
|
||||
}
|
||||
// LED Data
|
||||
_transactions[ 0 ].length = ( LED_FRAME_SIZE_BYTES * 8 ) * _count;
|
||||
_transactions[ 0 ].tx_buffer = _buffer;
|
||||
spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
|
||||
_transactions[0].length = (LED_FRAME_SIZE_BYTES * 8) * _count;
|
||||
_transactions[0].tx_buffer = _buffer;
|
||||
spi_device_queue_trans(_spi, _transactions + _transCount, portMAX_DELAY);
|
||||
_transCount++;
|
||||
|
||||
// 'latch'/start-of-data marker frames
|
||||
for ( int i = 0; i < _latchFrames; i++ ) {
|
||||
_transactions[ _transCount ].length = ( LATCH_FRAME_SIZE_BYTES * 8 );
|
||||
_transactions[ _transCount ].tx_buffer = _latchBuffer;
|
||||
spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
|
||||
for (int i = 0; i < _latchFrames; i++) {
|
||||
_transactions[_transCount].length = (LATCH_FRAME_SIZE_BYTES * 8);
|
||||
_transactions[_transCount].tx_buffer = _latchBuffer;
|
||||
spi_device_queue_trans(_spi, _transactions + _transCount, portMAX_DELAY);
|
||||
_transCount++;
|
||||
}
|
||||
}
|
||||
|
||||
spi_device_handle_t _spi;
|
||||
int _count;
|
||||
std::unique_ptr< LDP8806_GRB[] > _firstBuffer, _secondBuffer;
|
||||
LDP8806_GRB *_buffer;
|
||||
std::unique_ptr<LDP8806_GRB[]> _firstBuffer, _secondBuffer;
|
||||
LDP8806_GRB* _buffer;
|
||||
|
||||
spi_transaction_t _transactions[ TRANS_COUNT_MAX ];
|
||||
spi_transaction_t _transactions[TRANS_COUNT_MAX];
|
||||
int _transCount;
|
||||
|
||||
int _latchFrames;
|
||||
uint8_t _latchBuffer[ LATCH_FRAME_SIZE_BYTES ];
|
||||
uint8_t _latchBuffer[LATCH_FRAME_SIZE_BYTES];
|
||||
};
|
||||
|
||||
#endif //SMARTLEDS_H
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "server_mqtt.h"
|
||||
#endif //ENABLE_MQTT
|
||||
|
||||
#include "basic_auth.h"
|
||||
|
||||
static const char *TAG = "GPIO";
|
||||
QueueHandle_t gpio_queue_handle = NULL;
|
||||
@@ -458,7 +459,7 @@ void GpioHandler::registerGpioUri()
|
||||
httpd_uri_t camuri = { };
|
||||
camuri.method = HTTP_GET;
|
||||
camuri.uri = "/GPIO";
|
||||
camuri.handler = callHandleHttpRequest;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(callHandleHttpRequest);
|
||||
camuri.user_ctx = (void*)this;
|
||||
httpd_register_uri_handler(_httpServer, &camuri);
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ static camera_config_t camera_config = {
|
||||
.pixel_format = PIXFORMAT_JPEG, // YUV422,GRAYSCALE,RGB565,JPEG
|
||||
.frame_size = FRAMESIZE_VGA, // QQVGA-UXGA Do not use sizes above QVGA when not JPEG
|
||||
// .frame_size = FRAMESIZE_UXGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG
|
||||
.jpeg_quality = 6, // 0-63 lower number means higher quality
|
||||
.jpeg_quality = 12, // 0-63 lower number means higher quality
|
||||
.fb_count = 1, // if more than one, i2s runs in continuous mode. Use only with JPEG
|
||||
.fb_location = CAMERA_FB_IN_PSRAM, /*!< The location where the frame buffer will be allocated */
|
||||
.grab_mode = CAMERA_GRAB_LATEST, // only from new esp32cam version
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "ClassLogFile.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "basic_auth.h"
|
||||
|
||||
#include "../../include/defines.h"
|
||||
|
||||
static const char *TAG = "server_cam";
|
||||
@@ -280,27 +282,27 @@ void register_server_camera_uri(httpd_handle_t server)
|
||||
camuri.method = HTTP_GET;
|
||||
|
||||
camuri.uri = "/lighton";
|
||||
camuri.handler = handler_lightOn;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_lightOn);
|
||||
camuri.user_ctx = (void *)"Light On";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/lightoff";
|
||||
camuri.handler = handler_lightOff;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_lightOff);
|
||||
camuri.user_ctx = (void *)"Light Off";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/capture";
|
||||
camuri.handler = handler_capture;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_capture);
|
||||
camuri.user_ctx = NULL;
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/capture_with_flashlight";
|
||||
camuri.handler = handler_capture_with_light;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_capture_with_light);
|
||||
camuri.user_ctx = NULL;
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/save";
|
||||
camuri.handler = handler_capture_save_to_file;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_capture_save_to_file);
|
||||
camuri.user_ctx = NULL;
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ extern "C" {
|
||||
|
||||
#include "Helper.h"
|
||||
#include "miniz.h"
|
||||
#include "basic_auth.h"
|
||||
|
||||
static const char *TAG = "OTA FILE";
|
||||
|
||||
@@ -1174,7 +1175,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_uri_t file_download = {
|
||||
.uri = "/fileserver*", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = download_get_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(download_get_handler),
|
||||
.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &file_download);
|
||||
@@ -1183,7 +1184,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_uri_t file_datafileact = {
|
||||
.uri = "/datafileact", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = datafileact_get_full_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(datafileact_get_full_handler),
|
||||
.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &file_datafileact);
|
||||
@@ -1192,7 +1193,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_uri_t file_datafile_last_part_handle = {
|
||||
.uri = "/data", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = datafileact_get_last_part_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(datafileact_get_last_part_handler),
|
||||
.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &file_datafile_last_part_handle);
|
||||
@@ -1200,7 +1201,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_uri_t file_logfileact = {
|
||||
.uri = "/logfileact", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = logfileact_get_full_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(logfileact_get_full_handler),
|
||||
.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &file_logfileact);
|
||||
@@ -1209,7 +1210,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_uri_t file_logfile_last_part_handle = {
|
||||
.uri = "/log", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = logfileact_get_last_part_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(logfileact_get_last_part_handler),
|
||||
.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &file_logfile_last_part_handle);
|
||||
@@ -1219,7 +1220,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_uri_t file_upload = {
|
||||
.uri = "/upload/*", // Match all URIs of type /upload/path/to/file
|
||||
.method = HTTP_POST,
|
||||
.handler = upload_post_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(upload_post_handler),
|
||||
.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &file_upload);
|
||||
@@ -1228,7 +1229,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_uri_t file_delete = {
|
||||
.uri = "/delete/*", // Match all URIs of type /delete/path/to/file
|
||||
.method = HTTP_POST,
|
||||
.handler = delete_post_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(delete_post_handler),
|
||||
.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &file_delete);
|
||||
|
||||
@@ -42,6 +42,7 @@ https://docs.espressif.com/projects/esp-idf/en/latest/esp32/migration-guides/rel
|
||||
|
||||
#include "Helper.h"
|
||||
#include "statusled.h"
|
||||
#include "basic_auth.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
/*an ota data write buffer ready to write to the flash*/
|
||||
@@ -690,13 +691,13 @@ void register_server_ota_sdcard_uri(httpd_handle_t server)
|
||||
httpd_uri_t camuri = { };
|
||||
camuri.method = HTTP_GET;
|
||||
camuri.uri = "/ota";
|
||||
camuri.handler = handler_ota_update;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_ota_update);
|
||||
camuri.user_ctx = (void*) "Do OTA";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.method = HTTP_GET;
|
||||
camuri.uri = "/reboot";
|
||||
camuri.handler = handler_reboot;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_reboot);
|
||||
camuri.user_ctx = (void*) "Reboot";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
|
||||
@@ -65,11 +65,11 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
|
||||
|
||||
if (CNNType == Digit) {
|
||||
for (int i = 0; i < GENERAL[_analog]->ROI.size(); ++i) {
|
||||
if (GENERAL[_analog]->ROI[i]->result_klasse >= 10) {
|
||||
result = result + "N";
|
||||
if ((GENERAL[_analog]->ROI[i]->result_klasse >= 0) && (GENERAL[_analog]->ROI[i]->result_klasse < 10)) {
|
||||
result = result + std::to_string(GENERAL[_analog]->ROI[i]->result_klasse);
|
||||
}
|
||||
else {
|
||||
result = result + std::to_string(GENERAL[_analog]->ROI[i]->result_klasse);
|
||||
result = result + "N";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -78,7 +78,7 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
|
||||
if ((CNNType == DoubleHyprid10) || (CNNType == Digit100)) {
|
||||
float number = GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float;
|
||||
// NaN?
|
||||
if (number >= 0) {
|
||||
if ((number >= 0) && (number < 10)) {
|
||||
// is only set if it is the first digit (no analogue before!)
|
||||
if (_extendedResolution) {
|
||||
int result_after_decimal_point = ((int) floor(number * 10)) % 10;
|
||||
@@ -95,8 +95,15 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
|
||||
else {
|
||||
prev = PointerEvalHybridNew(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, prev, prev);
|
||||
}
|
||||
result = std::to_string(prev);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(dig100) prev=" + std::to_string(prev));
|
||||
|
||||
// is necessary because a number greater than 9.994999 returns a 10! (for further details see check in PointerEvalHybridNew)
|
||||
if ((prev >= 0) && (prev < 10)) {
|
||||
result = std::to_string(prev);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(dig100) prev=" + std::to_string(prev));
|
||||
}
|
||||
else {
|
||||
result = "N";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -107,7 +114,7 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
|
||||
}
|
||||
|
||||
for (int i = GENERAL[_analog]->ROI.size() - 2; i >= 0; --i) {
|
||||
if (GENERAL[_analog]->ROI[i]->result_float >= 0) {
|
||||
if ((GENERAL[_analog]->ROI[i]->result_float >= 0) && (GENERAL[_analog]->ROI[i]->result_float < 10)) {
|
||||
prev = PointerEvalHybridNew(GENERAL[_analog]->ROI[i]->result_float, GENERAL[_analog]->ROI[i+1]->result_float, prev);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout#PointerEvalHybridNew()= " + std::to_string(prev));
|
||||
result = std::to_string(prev) + result;
|
||||
@@ -117,7 +124,6 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
|
||||
prev = -1;
|
||||
result = "N" + result;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(result_float<0 /'N') result_float=" + std::to_string(GENERAL[_analog]->ROI[i]->result_float));
|
||||
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -150,6 +156,9 @@ int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_pred
|
||||
// on first digit is no spezial logic for transition needed
|
||||
// we use the recognition as given. The result is the int value of the recognition
|
||||
// add precisition of 2 digits and round before trunc
|
||||
// a number greater than 9.994999 is returned as 10, this leads to an error during the decimal shift because the NUMBERS[j]->ReturnRawValue is one digit longer.
|
||||
// To avoid this, an additional test must be carried out, see "if ((CNNType == DoubleHyprid10) || (CNNType == Digit100))" check in getReadout()
|
||||
// Another alternative would be "result = (int) ((int) trunc(round((number+10 % 10)*1000))) / 1000;", which could, however, lead to other errors?
|
||||
result = (int) ((int) trunc(round((number+10 % 10)*100)) ) / 100;
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalHybridNew - No predecessor - Result = " + std::to_string(result) +
|
||||
|
||||
@@ -26,6 +26,7 @@ extern "C" {
|
||||
|
||||
#include "server_help.h"
|
||||
#include "MainFlowControl.h"
|
||||
#include "basic_auth.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
static const char* TAG = "FLOWCTRL";
|
||||
|
||||
@@ -117,7 +117,12 @@ bool ClassFlowInfluxDB::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
// ESP_LOGD(TAG, "Init InfluxDB with uri: %s, measurement: %s, user: %s, password: %s", uri.c_str(), measurement.c_str(), user.c_str(), password.c_str());
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init InfluxDB with uri: " + uri + ", user: " + user + ", password: " + password);
|
||||
InfluxDBInit(uri, database, user, password);
|
||||
|
||||
/////////////////////// NEW //////////////////////////
|
||||
// InfluxDBInit(uri, database, user, password);
|
||||
influxDB.InfluxDBInitV1(uri, database, user, password);
|
||||
/////////////////////// NEW //////////////////////////
|
||||
|
||||
InfluxDBenable = true;
|
||||
} else {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB init skipped as we are missing some parameters");
|
||||
@@ -169,7 +174,12 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
|
||||
}
|
||||
|
||||
if (result.length() > 0)
|
||||
InfluxDBPublish(measurement, namenumber, result, timeutc);
|
||||
//////////////////////// NEW //////////////////////////
|
||||
// InfluxDBPublish(measurement, namenumber, result, timeutc);
|
||||
influxDB.InfluxDBPublish(measurement, namenumber, result, timeutc);
|
||||
//////////////////////// NEW //////////////////////////
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "ClassFlow.h"
|
||||
|
||||
#include "ClassFlowPostProcessing.h"
|
||||
#include "interface_influxdb.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -21,6 +22,8 @@ protected:
|
||||
std::string user, password;
|
||||
bool InfluxDBenable;
|
||||
|
||||
InfluxDB influxDB;
|
||||
|
||||
void SetInitialParameter(void);
|
||||
|
||||
void handleFieldname(string _decsep, string _value);
|
||||
|
||||
@@ -123,7 +123,14 @@ bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init InfluxDB with uri: " + uri + ", org: " + dborg + ", token: *****");
|
||||
// printf("vor V2 Init\n");
|
||||
InfluxDB_V2_Init(uri, bucket, dborg, dbtoken);
|
||||
|
||||
|
||||
////////////////////////////////////////// NEW ////////////////////////////////////////////
|
||||
// InfluxDB_V2_Init(uri, bucket, dborg, dbtoken);
|
||||
// InfluxDB_V2_Init(uri, bucket, dborg, dbtoken);
|
||||
influxdb.InfluxDBInitV2(uri, bucket, dborg, dbtoken);
|
||||
////////////////////////////////////////// NEW ////////////////////////////////////////////
|
||||
|
||||
// printf("nach V2 Init\n");
|
||||
InfluxDBenable = true;
|
||||
} else {
|
||||
@@ -232,7 +239,8 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
|
||||
printf("vor sende Influx_DB_V2 - namenumber. %s, result: %s, timestampt: %s", namenumber.c_str(), result.c_str(), resulttimestamp.c_str());
|
||||
|
||||
if (result.length() > 0)
|
||||
InfluxDB_V2_Publish(measurement, namenumber, result, resulttimeutc);
|
||||
influxdb.InfluxDBPublish(measurement, namenumber, result, resulttimeutc);
|
||||
// InfluxDB_V2_Publish(measurement, namenumber, result, resulttimeutc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "ClassFlowPostProcessing.h"
|
||||
|
||||
#include "interface_influxdb.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class ClassFlowInfluxDBv2 :
|
||||
@@ -21,6 +23,8 @@ protected:
|
||||
ClassFlowPostProcessing* flowpostprocessing;
|
||||
bool InfluxDBenable;
|
||||
|
||||
InfluxDB influxdb;
|
||||
|
||||
void SetInitialParameter(void);
|
||||
|
||||
void handleFieldname(string _decsep, string _value);
|
||||
|
||||
@@ -133,25 +133,25 @@ bool ClassFlowTakeImage::ReadParameter(FILE *pfile, string &aktparamgraph)
|
||||
switch (_ImageGainceiling_)
|
||||
{
|
||||
case 1:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_4X;
|
||||
CCstatus.ImageGainceiling = GAINCEILING_4X;
|
||||
break;
|
||||
case 2:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_8X;
|
||||
CCstatus.ImageGainceiling = GAINCEILING_8X;
|
||||
break;
|
||||
case 3:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_16X;
|
||||
CCstatus.ImageGainceiling = GAINCEILING_16X;
|
||||
break;
|
||||
case 4:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_32X;
|
||||
CCstatus.ImageGainceiling = GAINCEILING_32X;
|
||||
break;
|
||||
case 5:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_64X;
|
||||
CCstatus.ImageGainceiling = GAINCEILING_64X;
|
||||
break;
|
||||
case 6:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_128X;
|
||||
CCstatus.ImageGainceiling = GAINCEILING_128X;
|
||||
break;
|
||||
default:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_2X;
|
||||
CCstatus.ImageGainceiling = GAINCEILING_2X;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -251,7 +251,7 @@ bool ClassFlowTakeImage::ReadParameter(FILE *pfile, string &aktparamgraph)
|
||||
if (isStringNumeric(_ImageSpecialEffect))
|
||||
{
|
||||
int _ImageSpecialEffect_ = std::stoi(_ImageSpecialEffect);
|
||||
CFstatus.ImageSpecialEffect = clipInt(_ImageSpecialEffect_, 6, 0);
|
||||
CCstatus.ImageSpecialEffect = clipInt(_ImageSpecialEffect_, 6, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -293,7 +293,7 @@ bool ClassFlowTakeImage::ReadParameter(FILE *pfile, string &aktparamgraph)
|
||||
if (isStringNumeric(_ImageWbMode))
|
||||
{
|
||||
int _ImageWbMode_ = std::stoi(_ImageWbMode);
|
||||
CFstatus.ImageWbMode = clipInt(_ImageWbMode_, 4, 0);
|
||||
CCstatus.ImageWbMode = clipInt(_ImageWbMode_, 4, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "read_wlanini.h"
|
||||
#include "connect_wlan.h"
|
||||
#include "psram.h"
|
||||
#include "basic_auth.h"
|
||||
|
||||
// support IDF 5.x
|
||||
#ifndef portTICK_RATE_MS
|
||||
@@ -1280,7 +1281,7 @@ esp_err_t handler_editflow(httpd_req_t *req)
|
||||
int _ImageDenoiseLevel = std::stoi(_valuechar);
|
||||
if (CCstatus.CamSensor_id == OV2640_PID)
|
||||
{
|
||||
CCstatus.ImageDenoiseLevel = 0;
|
||||
CFstatus.ImageDenoiseLevel = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1782,108 +1783,108 @@ void register_server_main_flow_task_uri(httpd_handle_t server)
|
||||
camuri.method = HTTP_GET;
|
||||
|
||||
camuri.uri = "/doinit";
|
||||
camuri.handler = handler_init;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_init);
|
||||
camuri.user_ctx = (void *)"Light On";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
// Legacy API => New: "/setPreValue"
|
||||
camuri.uri = "/setPreValue.html";
|
||||
camuri.handler = handler_prevalue;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_prevalue);
|
||||
camuri.user_ctx = (void *)"Prevalue";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/setPreValue";
|
||||
camuri.handler = handler_prevalue;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_prevalue);
|
||||
camuri.user_ctx = (void *)"Prevalue";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/flow_start";
|
||||
camuri.handler = handler_flow_start;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_flow_start);
|
||||
camuri.user_ctx = (void *)"Flow Start";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/statusflow.html";
|
||||
camuri.handler = handler_statusflow;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_statusflow);
|
||||
camuri.user_ctx = (void *)"Light Off";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/statusflow";
|
||||
camuri.handler = handler_statusflow;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_statusflow);
|
||||
camuri.user_ctx = (void *)"Light Off";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
// Legacy API => New: "/cpu_temperature"
|
||||
camuri.uri = "/cputemp.html";
|
||||
camuri.handler = handler_cputemp;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_cputemp);
|
||||
camuri.user_ctx = (void *)"Light Off";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/cpu_temperature";
|
||||
camuri.handler = handler_cputemp;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_cputemp);
|
||||
camuri.user_ctx = (void *)"Light Off";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
// Legacy API => New: "/rssi"
|
||||
camuri.uri = "/rssi.html";
|
||||
camuri.handler = handler_rssi;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_rssi);
|
||||
camuri.user_ctx = (void *)"Light Off";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/rssi";
|
||||
camuri.handler = handler_rssi;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_rssi);
|
||||
camuri.user_ctx = (void *)"Light Off";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/date";
|
||||
camuri.handler = handler_current_date;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_current_date);
|
||||
camuri.user_ctx = (void *)"Light Off";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/uptime";
|
||||
camuri.handler = handler_uptime;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_uptime);
|
||||
camuri.user_ctx = (void *)"Light Off";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/editflow";
|
||||
camuri.handler = handler_editflow;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_editflow);
|
||||
camuri.user_ctx = (void *)"EditFlow";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
// Legacy API => New: "/value"
|
||||
camuri.uri = "/value.html";
|
||||
camuri.handler = handler_wasserzaehler;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_wasserzaehler);
|
||||
camuri.user_ctx = (void *)"Value";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/value";
|
||||
camuri.handler = handler_wasserzaehler;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_wasserzaehler);
|
||||
camuri.user_ctx = (void *)"Value";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
// Legacy API => New: "/value"
|
||||
camuri.uri = "/wasserzaehler.html";
|
||||
camuri.handler = handler_wasserzaehler;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_wasserzaehler);
|
||||
camuri.user_ctx = (void *)"Wasserzaehler";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/json";
|
||||
camuri.handler = handler_json;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_json);
|
||||
camuri.user_ctx = (void *)"JSON";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/heap";
|
||||
camuri.handler = handler_get_heap;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_get_heap);
|
||||
camuri.user_ctx = (void *)"Heap";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/stream";
|
||||
camuri.handler = handler_stream;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_stream);
|
||||
camuri.user_ctx = (void *)"stream";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
/** will handle metrics requests */
|
||||
camuri.uri = "/metrics";
|
||||
camuri.handler = handler_openmetrics;
|
||||
camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_openmetrics);
|
||||
camuri.user_ctx = (void *)"metrics";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ string toUpper(string in);
|
||||
|
||||
float temperatureRead();
|
||||
|
||||
std::string intToHexString(int _valueInt);
|
||||
time_t addDays(time_t startTime, int days);
|
||||
|
||||
void memCopyGen(uint8_t* _source, uint8_t* _target, int _size);
|
||||
|
||||
@@ -8,95 +8,35 @@
|
||||
#include "time_sntp.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
|
||||
static const char *TAG = "INFLUXDB";
|
||||
|
||||
std::string _influxDBURI;
|
||||
std::string _influxDBDatabase;
|
||||
std::string _influxDBUser;
|
||||
std::string _influxDBPassword;
|
||||
|
||||
std::string _influxDB_V2_URI;
|
||||
std::string _influxDB_V2_Bucket;
|
||||
std::string _influxDB_V2_Token;
|
||||
std::string _influxDB_V2_Org;
|
||||
|
||||
static esp_err_t http_event_handler(esp_http_client_event_t *evt);
|
||||
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token)
|
||||
{
|
||||
_influxDB_V2_URI = _uri;
|
||||
_influxDB_V2_Bucket = _bucket;
|
||||
_influxDB_V2_Org = _org;
|
||||
_influxDB_V2_Token = _token;
|
||||
}
|
||||
|
||||
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC)
|
||||
{
|
||||
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
||||
esp_http_client_config_t http_config = {
|
||||
.user_agent = "ESP32 Meter reader",
|
||||
.method = HTTP_METHOD_POST,
|
||||
.event_handler = http_event_handler,
|
||||
.buffer_size = MAX_HTTP_OUTPUT_BUFFER,
|
||||
.user_data = response_buffer
|
||||
};
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB_V2_Publish - Key: " + _key + ", Content: " + _content + ", timeUTC: " + std::to_string(_timeUTC));
|
||||
|
||||
std::string payload;
|
||||
char nowTimestamp[21];
|
||||
|
||||
if (_timeUTC > 0)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp (UTC): " + std::to_string(_timeUTC));
|
||||
sprintf(nowTimestamp,"%ld000000000", _timeUTC); // UTC
|
||||
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "no timestamp given");
|
||||
payload = _measurement + " " + _key + "=" + _content;
|
||||
}
|
||||
|
||||
payload.shrink_to_fit();
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
|
||||
|
||||
std::string apiURI = _influxDB_V2_URI + "/api/v2/write?org=" + _influxDB_V2_Org + "&bucket=" + _influxDB_V2_Bucket;
|
||||
apiURI.shrink_to_fit();
|
||||
http_config.url = apiURI.c_str();
|
||||
ESP_LOGI(TAG, "http_config: %s", http_config.url); // Add mark on log to see when it restarted
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "API URI: " + apiURI);
|
||||
|
||||
esp_http_client_handle_t http_client = esp_http_client_init(&http_config);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "client is initialized");
|
||||
|
||||
esp_http_client_set_header(http_client, "Content-Type", "text/plain");
|
||||
std::string _zw = "Token " + _influxDB_V2_Token;
|
||||
// LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Tokenheader: %s\n", _zw.c_str());
|
||||
esp_http_client_set_header(http_client, "Authorization", _zw.c_str());
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "header is set");
|
||||
|
||||
ESP_ERROR_CHECK(esp_http_client_set_post_field(http_client, payload.c_str(), payload.length()));
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "post payload is set");
|
||||
|
||||
esp_err_t err = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_http_client_perform(http_client));
|
||||
|
||||
if( err == ESP_OK ) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP request was performed");
|
||||
int status_code = esp_http_client_get_status_code(http_client);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP status code" + std::to_string(status_code));
|
||||
} else {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP request failed");
|
||||
}
|
||||
esp_http_client_cleanup(http_client);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Buffer to store the HTTP response.
|
||||
*
|
||||
* This character array is used to store the output of an HTTP response.
|
||||
* The size of the buffer is defined by the constant MAX_HTTP_OUTPUT_BUFFER.
|
||||
*/
|
||||
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
||||
|
||||
|
||||
/**
|
||||
* @brief HTTP event handler callback function.
|
||||
*
|
||||
* This function handles various HTTP client events and logs appropriate messages.
|
||||
*
|
||||
* @param evt Pointer to the HTTP client event structure.
|
||||
* @return esp_err_t ESP_OK on success.
|
||||
*
|
||||
* Event types handled:
|
||||
* - HTTP_EVENT_ERROR: Logs an error message when an HTTP error is encountered.
|
||||
* - HTTP_EVENT_ON_CONNECTED: Logs a message when the HTTP client successfully connects.
|
||||
* - HTTP_EVENT_HEADERS_SENT: Logs a message when all request headers are sent.
|
||||
* - HTTP_EVENT_ON_HEADER: Logs the received header key and value.
|
||||
* - HTTP_EVENT_ON_DATA: Logs the length of the received data.
|
||||
* - HTTP_EVENT_ON_FINISH: Logs a message when the HTTP client finishes the request.
|
||||
* - HTTP_EVENT_DISCONNECTED: Logs a message when the HTTP client disconnects.
|
||||
* - HTTP_EVENT_REDIRECT: Logs a message when an HTTP redirect occurs.
|
||||
*/
|
||||
static esp_err_t http_event_handler(esp_http_client_event_t *evt)
|
||||
{
|
||||
switch(evt->event_id)
|
||||
@@ -130,25 +70,123 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC) {
|
||||
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
||||
esp_http_client_config_t http_config = {
|
||||
.user_agent = "ESP32 Meter reader",
|
||||
.method = HTTP_METHOD_POST,
|
||||
.event_handler = http_event_handler,
|
||||
.buffer_size = MAX_HTTP_OUTPUT_BUFFER,
|
||||
.user_data = response_buffer
|
||||
};
|
||||
|
||||
if (_influxDBUser.length() && _influxDBPassword.length()){
|
||||
http_config.username = _influxDBUser.c_str();
|
||||
http_config.password = _influxDBPassword.c_str();
|
||||
http_config.auth_type = HTTP_AUTH_TYPE_BASIC;
|
||||
|
||||
/**
|
||||
* @brief Initializes the InfluxDB connection with version 1 settings.
|
||||
*
|
||||
* This function sets up the connection parameters for InfluxDB version 1.
|
||||
*
|
||||
* @param _influxDBURI The URI of the InfluxDB server.
|
||||
* @param _database The name of the database to connect to.
|
||||
* @param _user The username for authentication.
|
||||
* @param _password The password for authentication.
|
||||
*/
|
||||
void InfluxDB::InfluxDBInitV1(std::string _influxDBURI, std::string _database, std::string _user, std::string _password) {
|
||||
version = INFLUXDB_V1;
|
||||
influxDBURI = _influxDBURI;
|
||||
database = _database;
|
||||
user = _user;
|
||||
password = _password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the InfluxDB client with version 2 settings.
|
||||
*
|
||||
* This function sets up the InfluxDB client to use InfluxDB version 2 by
|
||||
* configuring the URI, bucket, organization, and token.
|
||||
*
|
||||
* @param _influxDBURI The URI of the InfluxDB server.
|
||||
* @param _bucket The bucket name to store data in.
|
||||
* @param _org The organization name associated with the bucket.
|
||||
* @param _token The authentication token for accessing the InfluxDB server.
|
||||
*/
|
||||
void InfluxDB::InfluxDBInitV2(std::string _influxDBURI, std::string _bucket, std::string _org, std::string _token) {
|
||||
version = INFLUXDB_V2;
|
||||
influxDBURI = _influxDBURI;
|
||||
bucket = _bucket;
|
||||
org = _org;
|
||||
token = _token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Establishes an HTTP connection to the InfluxDB server.
|
||||
*
|
||||
* This function configures and initializes an HTTP client to connect to the InfluxDB server.
|
||||
* It sets up the necessary parameters such as the URL, event handler, buffer size, and user data.
|
||||
* Depending on the InfluxDB version, it also configures the authentication type and credentials.
|
||||
*
|
||||
* @note This function destroys any existing HTTP client before initializing a new one.
|
||||
*
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void InfluxDB::connectHTTP() {
|
||||
esp_http_client_config_t config = {};
|
||||
|
||||
config.url = influxDBURI.c_str();
|
||||
config.event_handler = http_event_handler;
|
||||
config.buffer_size = MAX_HTTP_OUTPUT_BUFFER;
|
||||
config.user_data = response_buffer;
|
||||
|
||||
|
||||
switch (version) {
|
||||
case INFLUXDB_V1:
|
||||
config.auth_type = HTTP_AUTH_TYPE_BASIC;
|
||||
config.username = user.c_str();
|
||||
config.password = password.c_str();
|
||||
break;
|
||||
case INFLUXDB_V2:
|
||||
break;
|
||||
}
|
||||
|
||||
InfluxDBdestroy();
|
||||
httpClient = esp_http_client_init(&config);
|
||||
if (!httpClient) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to initialize HTTP client");
|
||||
} else {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "HTTP client initialized successfully");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Destroys the InfluxDB instance by cleaning up the HTTP client.
|
||||
*
|
||||
* This function checks if the HTTP client is initialized. If it is, it cleans up the HTTP client
|
||||
* and logs the cleanup action. The HTTP client pointer is then set to NULL.
|
||||
*/
|
||||
void InfluxDB::InfluxDBdestroy() {
|
||||
if (httpClient) {
|
||||
esp_http_client_cleanup(httpClient);
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "HTTP client cleaned up");
|
||||
httpClient = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Publishes data to an InfluxDB instance.
|
||||
*
|
||||
* This function sends a measurement, key, and content to an InfluxDB server.
|
||||
* It supports both InfluxDB v1 and v2 APIs.
|
||||
*
|
||||
* @param _measurement The measurement name to publish.
|
||||
* @param _key The key associated with the measurement.
|
||||
* @param _content The content or value to publish.
|
||||
* @param _timeUTC The timestamp in UTC. If greater than 0, it will be included in the payload.
|
||||
*
|
||||
* The function logs the process and handles HTTP communication with the InfluxDB server.
|
||||
* It constructs the appropriate API URI based on the InfluxDB version and sends the data
|
||||
* using an HTTP POST request.
|
||||
*/
|
||||
void InfluxDB::InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC) {
|
||||
std::string apiURI;
|
||||
std::string payload;
|
||||
char nowTimestamp[21];
|
||||
|
||||
connectHTTP();
|
||||
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", timeUTC: " + std::to_string(_timeUTC));
|
||||
|
||||
if (_timeUTC > 0)
|
||||
@@ -164,50 +202,47 @@ void InfluxDBPublish(std::string _measurement, std::string _key, std::string _co
|
||||
}
|
||||
|
||||
payload.shrink_to_fit();
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
|
||||
|
||||
esp_err_t err;
|
||||
|
||||
// use the default retention policy of the bucket
|
||||
std::string apiURI = _influxDBURI + "/write?db=" + _influxDBDatabase;
|
||||
// std::string apiURI = _influxDBURI + "/api/v2/write?bucket=" + _influxDBDatabase + "/";
|
||||
switch (version) {
|
||||
case INFLUXDB_V1:
|
||||
apiURI = influxDBURI + "/write?db=" + database;
|
||||
apiURI.shrink_to_fit();
|
||||
|
||||
apiURI.shrink_to_fit();
|
||||
http_config.url = apiURI.c_str();
|
||||
esp_http_client_set_url(httpClient, apiURI.c_str());
|
||||
esp_http_client_set_method(httpClient, HTTP_METHOD_POST);
|
||||
esp_http_client_set_header(httpClient, "Content-Type", "text/plain");
|
||||
esp_http_client_set_post_field(httpClient, payload.c_str(), payload.length());
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "API URI: " + apiURI);
|
||||
err = esp_http_client_perform(httpClient);
|
||||
if (err == ESP_OK) {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Data published successfully: " + payload);
|
||||
} else {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to publish data: " + std::string(esp_err_to_name(err)));
|
||||
}
|
||||
break;
|
||||
|
||||
esp_http_client_handle_t http_client = esp_http_client_init(&http_config);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "client is initialized");
|
||||
case INFLUXDB_V2:
|
||||
apiURI = influxDBURI + "/api/v2/write?org=" + org + "&bucket=" + bucket;
|
||||
apiURI.shrink_to_fit();
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "apiURI: " + apiURI);
|
||||
|
||||
esp_http_client_set_header(http_client, "Content-Type", "text/plain");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "header is set");
|
||||
|
||||
ESP_ERROR_CHECK(esp_http_client_set_post_field(http_client, payload.c_str(), payload.length()));
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "post payload is set");
|
||||
|
||||
esp_err_t err = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_http_client_perform(http_client));
|
||||
|
||||
if( err == ESP_OK ) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP request was performed");
|
||||
int status_code = esp_http_client_get_status_code(http_client);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP status code" + std::to_string(status_code));
|
||||
} else {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP request failed");
|
||||
esp_http_client_set_url(httpClient, apiURI.c_str());
|
||||
esp_http_client_set_method(httpClient, HTTP_METHOD_POST);
|
||||
esp_http_client_set_header(httpClient, "Content-Type", "text/plain");
|
||||
std::string _zw = "Token " + token;
|
||||
esp_http_client_set_header(httpClient, "Authorization", _zw.c_str());
|
||||
esp_http_client_set_post_field(httpClient, payload.c_str(), payload.length());
|
||||
err = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_http_client_perform(httpClient));
|
||||
if (err == ESP_OK) {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Data published successfully: " + payload);
|
||||
} else {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Failed to publish data: " + std::string(esp_err_to_name(err)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
esp_http_client_cleanup(http_client);
|
||||
}
|
||||
|
||||
|
||||
void InfluxDBInit(std::string _uri, std::string _database, std::string _user, std::string _password){
|
||||
_influxDBURI = _uri;
|
||||
_influxDBDatabase = _database;
|
||||
_influxDBUser = _user;
|
||||
_influxDBPassword = _password;
|
||||
|
||||
}
|
||||
|
||||
void InfluxDBdestroy() {
|
||||
}
|
||||
|
||||
#endif //ENABLE_INFLUXDB
|
||||
|
||||
@@ -8,17 +8,106 @@
|
||||
#include <map>
|
||||
#include <functional>
|
||||
|
||||
// Interface to InfluxDB v1.x
|
||||
void InfluxDBInit(std::string _influxDBURI, std::string _database, std::string _user, std::string _password);
|
||||
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC);
|
||||
|
||||
// Interface to InfluxDB v2.x
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token);
|
||||
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC);
|
||||
#include <string>
|
||||
#include "esp_http_client.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
|
||||
enum InfluxDBVersion {
|
||||
INFLUXDB_V1,
|
||||
INFLUXDB_V2
|
||||
};
|
||||
|
||||
/**
|
||||
* @class InfluxDB
|
||||
* @brief A class to handle connections and data publishing to InfluxDB servers.
|
||||
*
|
||||
* This class supports both InfluxDB v1.x and v2.x versions. It provides methods to initialize
|
||||
* the connection parameters, publish data, and destroy the connection.
|
||||
*
|
||||
* @private
|
||||
* @var std::string influxDBURI
|
||||
* URI for the InfluxDB server.
|
||||
*
|
||||
* @var std::string database
|
||||
* Database name for InfluxDB v1.x.
|
||||
*
|
||||
* @var std::string user
|
||||
* Username for InfluxDB v1.x.
|
||||
*
|
||||
* @var std::string password
|
||||
* Password for InfluxDB v1.x.
|
||||
*
|
||||
* @var std::string bucket
|
||||
* Bucket name for InfluxDB v2.x.
|
||||
*
|
||||
* @var std::string org
|
||||
* Organization name for InfluxDB v2.x.
|
||||
*
|
||||
* @var std::string token
|
||||
* Token for InfluxDB v2.x.
|
||||
*
|
||||
* @var InfluxDBVersion version
|
||||
* Version of the InfluxDB server (v1.x or v2.x).
|
||||
*
|
||||
* @var esp_http_client_handle_t httpClient
|
||||
* HTTP client handle for making requests to the InfluxDB server.
|
||||
*
|
||||
* @var void connectHTTP()
|
||||
* Establishes an HTTP connection to the InfluxDB server.
|
||||
*
|
||||
* @public
|
||||
* @fn void InfluxDBInitV1(std::string _influxDBURI, std::string _database, std::string _user, std::string _password)
|
||||
* Initializes the connection parameters for InfluxDB v1.x.
|
||||
*
|
||||
* @fn void InfluxDBInitV2(std::string _influxDBURI, std::string _bucket, std::string _org, std::string _token)
|
||||
* Initializes the connection parameters for InfluxDB v2.x.
|
||||
*
|
||||
* @fn void InfluxDBdestroy()
|
||||
* Destroys the InfluxDB connection.
|
||||
*
|
||||
* @fn void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC)
|
||||
* Publishes data to the InfluxDB server.
|
||||
*
|
||||
* @param _measurement The measurement name.
|
||||
* @param _key The key for the data point.
|
||||
* @param _content The content or value of the data point.
|
||||
* @param _timeUTC The timestamp in UTC for the data point.
|
||||
*/
|
||||
|
||||
class InfluxDB {
|
||||
private:
|
||||
// Information for InfluxDB v1.x
|
||||
std::string influxDBURI = "";
|
||||
// Information for InfluxDB v1.x
|
||||
std::string database = "";
|
||||
std::string user = "";
|
||||
std::string password = "";
|
||||
|
||||
// Information for InfluxDB v2.x
|
||||
std::string bucket = "";
|
||||
std::string org = "";
|
||||
std::string token = "";
|
||||
|
||||
InfluxDBVersion version;
|
||||
|
||||
esp_http_client_handle_t httpClient = NULL;
|
||||
|
||||
void connectHTTP();
|
||||
|
||||
public:
|
||||
// Initialize the InfluxDB connection parameters
|
||||
void InfluxDBInitV1(std::string _influxDBURI, std::string _database, std::string _user, std::string _password);
|
||||
void InfluxDBInitV2(std::string _influxDBURI, std::string _bucket, std::string _org, std::string _token);
|
||||
|
||||
// Destroy the InfluxDB connection
|
||||
void InfluxDBdestroy();
|
||||
// Publish data to the InfluxDB server
|
||||
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC);
|
||||
};
|
||||
|
||||
|
||||
void InfluxDBdestroy();
|
||||
|
||||
#endif //INTERFACE_INFLUXDB_H
|
||||
#endif //ENABLE_INFLUXDB
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "interface_mqtt.h"
|
||||
#include "time_sntp.h"
|
||||
#include "../../include/defines.h"
|
||||
#include "basic_auth.h"
|
||||
|
||||
|
||||
|
||||
@@ -347,7 +348,7 @@ void register_server_mqtt_uri(httpd_handle_t server) {
|
||||
uri.method = HTTP_GET;
|
||||
|
||||
uri.uri = "/mqtt_publish_discovery";
|
||||
uri.handler = scheduleSendingDiscovery_and_static_Topics;
|
||||
uri.handler = APPLY_BASIC_AUTH_FILTER(scheduleSendingDiscovery_and_static_Topics);
|
||||
uri.user_ctx = (void*) "";
|
||||
httpd_register_uri_handler(server, &uri);
|
||||
}
|
||||
|
||||
107
code/components/jomjol_wlan/basic_auth.cpp
Normal file
107
code/components/jomjol_wlan/basic_auth.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
#include "basic_auth.h"
|
||||
#include "read_wlanini.h"
|
||||
#include <esp_tls_crypto.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
|
||||
#define HTTPD_401 "401 UNAUTHORIZED"
|
||||
|
||||
static const char *TAG = "HTTPAUTH";
|
||||
|
||||
typedef struct {
|
||||
const char *username;
|
||||
const char *password;
|
||||
} basic_auth_info_t;
|
||||
|
||||
basic_auth_info_t basic_auth_info = { NULL, NULL };
|
||||
|
||||
void init_basic_auth() {
|
||||
if (!wlan_config.http_username.empty() && !wlan_config.http_password.empty()) {
|
||||
basic_auth_info.username = wlan_config.http_username.c_str();
|
||||
basic_auth_info.password = wlan_config.http_password.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
static char *http_auth_basic(const char *username, const char *password)
|
||||
{
|
||||
int out;
|
||||
char *user_info = NULL;
|
||||
char *digest = NULL;
|
||||
size_t n = 0;
|
||||
asprintf(&user_info, "%s:%s", username, password);
|
||||
if (!user_info) {
|
||||
ESP_LOGE(TAG, "No enough memory for user information");
|
||||
return NULL;
|
||||
}
|
||||
esp_crypto_base64_encode(NULL, 0, &n, (const unsigned char *)user_info, strlen(user_info));
|
||||
|
||||
/* 6: The length of the "Basic " string
|
||||
* n: Number of bytes for a base64 encode format
|
||||
* 1: Number of bytes for a reserved which be used to fill zero
|
||||
*/
|
||||
digest = static_cast<char*>(calloc(1, 6 + n + 1));
|
||||
if (digest) {
|
||||
strcpy(digest, "Basic ");
|
||||
esp_crypto_base64_encode((unsigned char *)digest + 6, n, (size_t *)&out, (const unsigned char *)user_info, strlen(user_info));
|
||||
}
|
||||
free(user_info);
|
||||
return digest;
|
||||
}
|
||||
|
||||
esp_err_t basic_auth_request_filter(httpd_req_t *req, esp_err_t original_handler(httpd_req_t *))
|
||||
{
|
||||
char *buf = NULL;
|
||||
size_t buf_len = 0;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
char unauthorized[] = "You are not authorized to use this website!";
|
||||
|
||||
if (basic_auth_info.username == NULL || basic_auth_info.password == NULL) {
|
||||
ret = original_handler(req);
|
||||
} else {
|
||||
buf_len = httpd_req_get_hdr_value_len(req, "Authorization") + 1;
|
||||
if (buf_len > 1) {
|
||||
buf = static_cast<char*>(calloc(1, buf_len));
|
||||
if (!buf) {
|
||||
ESP_LOGE(TAG, "No enough memory for basic authorization");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
if (httpd_req_get_hdr_value_str(req, "Authorization", buf, buf_len) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Found header => Authorization: %s", buf);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "No auth value received");
|
||||
}
|
||||
|
||||
char *auth_credentials = http_auth_basic(basic_auth_info.username, basic_auth_info.password);
|
||||
if (!auth_credentials) {
|
||||
ESP_LOGE(TAG, "No enough memory for basic authorization credentials");
|
||||
free(buf);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
if (strncmp(auth_credentials, buf, buf_len)) {
|
||||
ESP_LOGE(TAG, "Not authenticated");
|
||||
httpd_resp_set_status(req, HTTPD_401);
|
||||
httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
|
||||
httpd_resp_set_hdr(req, "Connection", "keep-alive");
|
||||
httpd_resp_set_hdr(req, "WWW-Authenticate", "Basic realm=\"AIOTED\"");
|
||||
httpd_resp_send(req, unauthorized, strlen(unauthorized));
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Authenticated calling http handler now!");
|
||||
ret=original_handler(req);
|
||||
}
|
||||
free(auth_credentials);
|
||||
free(buf);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "No auth header received");
|
||||
httpd_resp_set_status(req, HTTPD_401);
|
||||
httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
|
||||
httpd_resp_set_hdr(req, "Connection", "keep-alive");
|
||||
httpd_resp_set_hdr(req, "WWW-Authenticate", "Basic realm=\"AIOTED\"");
|
||||
httpd_resp_send(req, unauthorized, strlen(unauthorized));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
8
code/components/jomjol_wlan/basic_auth.h
Normal file
8
code/components/jomjol_wlan/basic_auth.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <esp_http_server.h>
|
||||
|
||||
void init_basic_auth();
|
||||
esp_err_t basic_auth_request_filter(httpd_req_t *req, esp_err_t original_handler(httpd_req_t *));
|
||||
|
||||
#define APPLY_BASIC_AUTH_FILTER(method) [](httpd_req_t *req){ return basic_auth_request_filter(req, method); }
|
||||
@@ -49,6 +49,9 @@
|
||||
#define ets_delay_us(a) esp_rom_delay_us(a)
|
||||
#endif
|
||||
|
||||
#include "../esp-protocols/components/mdns/include/mdns.h"
|
||||
|
||||
|
||||
static const char *TAG = "WIFI";
|
||||
|
||||
static bool APWithBetterRSSI = false;
|
||||
@@ -657,6 +660,14 @@ esp_err_t wifi_init_sta(void)
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Set hostname to: " + wlan_config.hostname);
|
||||
}
|
||||
//initialize mDNS service
|
||||
retval = mdns_init();
|
||||
if (retval != ESP_OK) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "mdns_init failed! Error: " + std::to_string(retval));
|
||||
} else {
|
||||
//set mdns hostname
|
||||
mdns_hostname_set(wlan_config.hostname.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Init successful");
|
||||
|
||||
@@ -145,6 +145,29 @@ int LoadWlanFromFile(std::string fn)
|
||||
wlan_config.dns = tmp;
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "DNS: " + wlan_config.dns);
|
||||
}
|
||||
|
||||
else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "HTTP_USERNAME")){
|
||||
tmp = splitted[1];
|
||||
if ((tmp[0] == '"') && (tmp[tmp.length()-1] == '"')){
|
||||
tmp = tmp.substr(1, tmp.length()-2);
|
||||
}
|
||||
wlan_config.http_username = tmp;
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "HTTP_USERNAME: " + wlan_config.http_username);
|
||||
}
|
||||
|
||||
else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "HTTP_PASSWORD")){
|
||||
tmp = splitted[1];
|
||||
if ((tmp[0] == '"') && (tmp[tmp.length()-1] == '"')){
|
||||
tmp = tmp.substr(1, tmp.length()-2);
|
||||
}
|
||||
wlan_config.http_password = tmp;
|
||||
#ifndef __HIDE_PASSWORD
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "HTTP_PASSWORD: " + wlan_config.http_password);
|
||||
#else
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "HTTP_PASSWORD: XXXXXXXX");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (defined WLAN_USE_ROAMING_BY_SCANNING || (defined WLAN_USE_MESH_ROAMING && defined WLAN_USE_MESH_ROAMING_ACTIVATE_CLIENT_TRIGGERED_QUERIES))
|
||||
else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "RSSITHRESHOLD")){
|
||||
tmp = trim(splitted[1]);
|
||||
|
||||
@@ -13,6 +13,8 @@ struct wlan_config {
|
||||
std::string gateway = "";
|
||||
std::string netmask = "";
|
||||
std::string dns = "";
|
||||
std::string http_username = "";
|
||||
std::string http_password = "";
|
||||
int rssi_threshold = 0; // Default: 0 -> ROAMING disabled
|
||||
};
|
||||
extern struct wlan_config wlan_config;
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
dependencies:
|
||||
espressif/esp-nn:
|
||||
component_hash: b32869798bdb40dec6bc99caca48cd65d42f8a9f506b9ab9c598a076f891ede9
|
||||
component_hash: f6f2851ce82137a66e4265071c9b852bbe0130b882a18dea9f03faea7bf1295a
|
||||
source:
|
||||
pre_release: true
|
||||
service_url: https://api.components.espressif.com/
|
||||
type: service
|
||||
version: 1.0.2
|
||||
version: 1.1.0
|
||||
idf:
|
||||
component_hash: null
|
||||
source:
|
||||
type: idf
|
||||
version: 5.3.1
|
||||
manifest_hash: 6995555b9b41e897235448c868ca92c0c3401fd2ff90df084be9bb8629958f2c
|
||||
manifest_hash: f88c9e5c2d75a9d5d6968fc67a90ef0cd7146dd6a3905a79c4dfcfc3b4fe6731
|
||||
target: esp32
|
||||
version: 1.0.0
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
#include "configFile.h"
|
||||
#include "server_main.h"
|
||||
#include "server_camera.h"
|
||||
#include "basic_auth.h"
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
#include "server_mqtt.h"
|
||||
#endif //ENABLE_MQTT
|
||||
@@ -77,10 +79,10 @@
|
||||
static heap_trace_record_t trace_record[NUM_RECORDS]; // This buffer must be in internal RAM
|
||||
#endif
|
||||
|
||||
extern const char* GIT_TAG;
|
||||
extern const char* GIT_REV;
|
||||
extern const char* GIT_BRANCH;
|
||||
extern const char* BUILD_TIME;
|
||||
extern const char *GIT_TAG;
|
||||
extern const char *GIT_REV;
|
||||
extern const char *GIT_BRANCH;
|
||||
extern const char *BUILD_TIME;
|
||||
|
||||
extern std::string getFwVersion(void);
|
||||
extern std::string getHTMLversion(void);
|
||||
@@ -107,27 +109,51 @@ bool Init_NVS_SDCard()
|
||||
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
||||
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
|
||||
|
||||
// For SoCs where the SD power can be supplied both via an internal or external (e.g. on-board LDO) power supply.
|
||||
// When using specific IO pins (which can be used for ultra high-speed SDMMC) to connect to the SD card
|
||||
// and the internal LDO power supply, we need to initialize the power supply first.
|
||||
#if SD_PWR_CTRL_LDO_INTERNAL_IO
|
||||
sd_pwr_ctrl_ldo_config_t ldo_config = {
|
||||
.ldo_chan_id = CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_IO_ID,
|
||||
};
|
||||
sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;
|
||||
|
||||
ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to create a new on-chip LDO power control driver");
|
||||
return ret;
|
||||
}
|
||||
host.pwr_ctrl_handle = pwr_ctrl_handle;
|
||||
#endif
|
||||
|
||||
// This initializes the slot without card detect (CD) and write protect (WP) signals.
|
||||
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
|
||||
#ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
|
||||
sdmmc_slot_config_t slot_config = {
|
||||
.cd = SDMMC_SLOT_NO_CD,
|
||||
.wp = SDMMC_SLOT_NO_WP,
|
||||
};
|
||||
#else
|
||||
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
|
||||
#endif
|
||||
|
||||
// Set bus width to use:
|
||||
#ifdef __SD_USE_ONE_LINE_MODE__
|
||||
slot_config.width = 1;
|
||||
#ifdef SOC_SDMMC_USE_GPIO_MATRIX
|
||||
#ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
|
||||
slot_config.clk = GPIO_SDCARD_CLK;
|
||||
slot_config.cmd = GPIO_SDCARD_CMD;
|
||||
slot_config.d0 = GPIO_SDCARD_D0;
|
||||
#endif
|
||||
|
||||
#else
|
||||
#endif // end CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
|
||||
#else // else __SD_USE_ONE_LINE_MODE__
|
||||
slot_config.width = 4;
|
||||
#ifdef SOC_SDMMC_USE_GPIO_MATRIX
|
||||
#ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
|
||||
slot_config.d1 = GPIO_SDCARD_D1;
|
||||
slot_config.d2 = GPIO_SDCARD_D2;
|
||||
slot_config.d3 = GPIO_SDCARD_D3;
|
||||
#endif
|
||||
#endif
|
||||
#endif // end CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
|
||||
#endif // end __SD_USE_ONE_LINE_MODE__
|
||||
|
||||
// Enable internal pullups on enabled pins. The internal pullups
|
||||
// are insufficient however, please make sure 10k external pullups are
|
||||
@@ -430,6 +456,8 @@ extern "C" void app_main(void)
|
||||
StatusLED(WLAN_INIT, 3, true);
|
||||
return;
|
||||
}
|
||||
|
||||
init_basic_auth();
|
||||
}
|
||||
else if (iWLANStatus == -1) { // wlan.ini not available, potentially empty or content not readable
|
||||
StatusLED(WLAN_INIT, 1, true);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "MainFlowControl.h"
|
||||
#include "esp_log.h"
|
||||
#include "basic_auth.h"
|
||||
#include "esp_chip_info.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -408,7 +409,7 @@ void register_server_main_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_uri_t info_get_handle = {
|
||||
.uri = "/info", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = info_get_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(info_get_handler),
|
||||
.user_ctx = (void*) base_path // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &info_get_handle);
|
||||
@@ -416,7 +417,7 @@ void register_server_main_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_uri_t sysinfo_handle = {
|
||||
.uri = "/sysinfo", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = sysinfo_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(sysinfo_handler),
|
||||
.user_ctx = (void*) base_path // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &sysinfo_handle);
|
||||
@@ -424,7 +425,7 @@ void register_server_main_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_uri_t starttime_tmp_handle = {
|
||||
.uri = "/starttime", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = starttime_get_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(starttime_get_handler),
|
||||
.user_ctx = NULL // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &starttime_tmp_handle);
|
||||
@@ -432,7 +433,7 @@ void register_server_main_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_uri_t img_tmp_handle = {
|
||||
.uri = "/img_tmp/*", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = img_tmp_virtual_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(img_tmp_virtual_handler),
|
||||
.user_ctx = (void*) base_path // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &img_tmp_handle);
|
||||
@@ -440,7 +441,7 @@ void register_server_main_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_uri_t main_rest_handle = {
|
||||
.uri = "/*", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = hello_main_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(hello_main_handler),
|
||||
.user_ctx = (void*) base_path // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &main_rest_handle);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "Helper.h"
|
||||
#include "statusled.h"
|
||||
#include "server_ota.h"
|
||||
#include "basic_auth.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
@@ -468,7 +469,7 @@ httpd_handle_t start_webserverAP(void)
|
||||
httpd_uri_t reboot_handle = {
|
||||
.uri = "/reboot", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = reboot_handlerAP,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(reboot_handlerAP),
|
||||
.user_ctx = NULL // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &reboot_handle);
|
||||
@@ -476,7 +477,7 @@ httpd_handle_t start_webserverAP(void)
|
||||
httpd_uri_t config_ini_handle = {
|
||||
.uri = "/config", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = config_ini_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(config_ini_handler),
|
||||
.user_ctx = NULL // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &config_ini_handle);
|
||||
@@ -485,7 +486,7 @@ httpd_handle_t start_webserverAP(void)
|
||||
httpd_uri_t file_uploadAP = {
|
||||
.uri = "/upload/*", // Match all URIs of type /upload/path/to/file
|
||||
.method = HTTP_POST,
|
||||
.handler = upload_post_handlerAP,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(upload_post_handlerAP),
|
||||
.user_ctx = NULL // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &file_uploadAP);
|
||||
@@ -493,7 +494,7 @@ httpd_handle_t start_webserverAP(void)
|
||||
httpd_uri_t test_uri = {
|
||||
.uri = "*",
|
||||
.method = HTTP_GET,
|
||||
.handler = test_handler,
|
||||
.handler = APPLY_BASIC_AUTH_FILTER(test_handler),
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(server, &test_uri);
|
||||
|
||||
@@ -133,7 +133,25 @@ CONFIG_MQTT_USE_CUSTOM_CONFIG=y
|
||||
CONFIG_MBEDTLS_HAVE_TIME=y
|
||||
CONFIG_MBEDTLS_HAVE_TIME_DATE=y
|
||||
|
||||
CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=n
|
||||
#
|
||||
# ESP-Driver:LEDC Configurations
|
||||
#
|
||||
CONFIG_LEDC_CTRL_FUNC_IN_IRAM=y
|
||||
# end of ESP-Driver:LEDC Configurations
|
||||
|
||||
#
|
||||
# Legacy RMT Driver Configurations
|
||||
#
|
||||
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of Legacy RMT Driver Configurations
|
||||
|
||||
#
|
||||
# ESP-Driver:RMT Configurations
|
||||
#
|
||||
CONFIG_RMT_ISR_IRAM_SAFE=y
|
||||
CONFIG_RMT_RECV_FUNC_IN_IRAM=y
|
||||
# CONFIG_RMT_ENABLE_DEBUG_LOG is not set
|
||||
# end of ESP-Driver:RMT Configurations
|
||||
|
||||
CONFIG_CAMERA_CORE0=n
|
||||
CONFIG_CAMERA_CORE1=y
|
||||
@@ -162,6 +180,7 @@ CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=4864
|
||||
#CONFIG_FREERTOS_USE_TRACE_FACILITY=1
|
||||
#CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
|
||||
#CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y
|
||||
CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=n
|
||||
|
||||
#force disable HIMEM as not used in default config, can be enabled with [env:esp32cam-dev-himem]
|
||||
#free 256kb of internal memory :
|
||||
|
||||
Reference in New Issue
Block a user