@ -0,0 +1,41 @@ | |||
# Number of days of inactivity before an Issue or Pull Request becomes stale | |||
daysUntilStale: 120 | |||
# Number of days of inactivity before a stale Issue or Pull Request is closed. | |||
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. | |||
daysUntilClose: 30 | |||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable | |||
exemptLabels: | |||
- enhancement | |||
- bug | |||
- staged for release | |||
# Set to true to ignore issues in a project (defaults to false) | |||
exemptProjects: false | |||
# Set to true to ignore issues in a milestone (defaults to false) | |||
exemptMilestones: false | |||
# Label to use when marking as stale | |||
staleLabel: stale | |||
# Comment to post when marking as stale. Set to `false` to disable | |||
markComment: > | |||
This issue has been automatically marked as stale because it has not had | |||
recent activity. It will be closed in 30 days if no further activity occurs. | |||
Thank you for your contributions. | |||
# Comment to post when removing the stale label. | |||
# unmarkComment: > | |||
# Your comment here. | |||
# Comment to post when closing a stale Issue or Pull Request. | |||
closeComment: > | |||
This issue will be auto-closed because there hasn't been any activity for a few months. Feel free to open a new one if you still experience this problem. | |||
# Limit the number of actions per hour, from 1-30. Default is 30 | |||
limitPerRun: 30 | |||
# Limit to only `issues` or `pulls` | |||
only: issues |
@ -0,0 +1,19 @@ | |||
/* Flash Split for 1M chips, no SPIFFS */ | |||
/* sketch 995KB */ | |||
/* eeprom 8KB */ | |||
/* reserved 16KB */ | |||
MEMORY | |||
{ | |||
dport0_0_seg : org = 0x3FF00000, len = 0x10 | |||
dram0_0_seg : org = 0x3FFE8000, len = 0x14000 | |||
iram1_0_seg : org = 0x40100000, len = 0x8000 | |||
irom0_0_seg : org = 0x40201010, len = 0xf8ff0 | |||
} | |||
PROVIDE ( _SPIFFS_start = 0x402FA000 ); | |||
PROVIDE ( _SPIFFS_end = 0x402FA000 ); | |||
PROVIDE ( _SPIFFS_page = 0 ); | |||
PROVIDE ( _SPIFFS_block = 0 ); | |||
INCLUDE "../ld/eagle.app.v6.common.ld" |
@ -0,0 +1,21 @@ | |||
/* Flash Split for 4M chips */ | |||
/* sketch 1019KB */ | |||
/* empty/ota? 2048KB */ | |||
/* spiffs 992KB */ | |||
/* eeprom 16KB */ | |||
/* reserved 16KB */ | |||
MEMORY | |||
{ | |||
dport0_0_seg : org = 0x3FF00000, len = 0x10 | |||
dram0_0_seg : org = 0x3FFE8000, len = 0x14000 | |||
iram1_0_seg : org = 0x40100000, len = 0x8000 | |||
irom0_0_seg : org = 0x40201010, len = 0xfeff0 | |||
} | |||
PROVIDE ( _SPIFFS_start = 0x40500000 ); | |||
PROVIDE ( _SPIFFS_end = 0x405F8000 ); | |||
PROVIDE ( _SPIFFS_page = 0x100 ); | |||
PROVIDE ( _SPIFFS_block = 0x2000 ); | |||
INCLUDE "../ld/eagle.app.v6.common.ld" |
@ -0,0 +1,20 @@ | |||
/* Flash Split for 4M chips */ | |||
/* sketch 1019KB */ | |||
/* spiffs 3040KB */ | |||
/* eeprom 16KB */ | |||
/* reserved 16KB */ | |||
MEMORY | |||
{ | |||
dport0_0_seg : org = 0x3FF00000, len = 0x10 | |||
dram0_0_seg : org = 0x3FFE8000, len = 0x14000 | |||
iram1_0_seg : org = 0x40100000, len = 0x8000 | |||
irom0_0_seg : org = 0x40201010, len = 0xfeff0 | |||
} | |||
PROVIDE ( _SPIFFS_start = 0x40300000 ); | |||
PROVIDE ( _SPIFFS_end = 0x405F8000 ); | |||
PROVIDE ( _SPIFFS_page = 0x100 ); | |||
PROVIDE ( _SPIFFS_block = 0x2000 ); | |||
INCLUDE "../ld/eagle.app.v6.common.ld" |
@ -0,0 +1,18 @@ | |||
/* Flash Split for 512K chips */ | |||
/* sketch 487KB */ | |||
/* eeprom 20KB */ | |||
MEMORY | |||
{ | |||
dport0_0_seg : org = 0x3FF00000, len = 0x10 | |||
dram0_0_seg : org = 0x3FFE8000, len = 0x14000 | |||
iram1_0_seg : org = 0x40100000, len = 0x8000 | |||
irom0_0_seg : org = 0x40201010, len = 0x79ff0 | |||
} | |||
PROVIDE ( _SPIFFS_start = 0x4027B000 ); | |||
PROVIDE ( _SPIFFS_end = 0x4027B000 ); | |||
PROVIDE ( _SPIFFS_page = 0x0 ); | |||
PROVIDE ( _SPIFFS_block = 0x0 ); | |||
INCLUDE "../ld/eagle.app.v6.common.ld" |
@ -1,5 +1,5 @@ | |||
#define APP_NAME "ESPURNA" | |||
#define APP_VERSION "1.12.6" | |||
#define APP_VERSION "1.13.0c" | |||
#define APP_REVISION "db84006" | |||
#define APP_AUTHOR "xose.perez@gmail.com" | |||
#define APP_WEBSITE "http://tinkerman.cat" | |||
@ -0,0 +1,86 @@ | |||
/* | |||
EEPROM MODULE | |||
*/ | |||
#include <EEPROM_Rotate.h> | |||
// ----------------------------------------------------------------------------- | |||
bool eepromRotate(bool value) { | |||
// Enable/disable EEPROM rotation only if we are using more sectors than the | |||
// reserved by the memory layout | |||
if (EEPROMr.size() > EEPROMr.reserved()) { | |||
if (value) { | |||
DEBUG_MSG_P(PSTR("[EEPROM] Reenabling EEPROM rotation\n")); | |||
} else { | |||
DEBUG_MSG_P(PSTR("[EEPROM] Disabling EEPROM rotation\n")); | |||
} | |||
EEPROMr.rotate(value); | |||
} | |||
} | |||
String eepromSectors() { | |||
String response; | |||
for (uint32_t i = 0; i < EEPROMr.size(); i++) { | |||
if (i > 0) response = response + String(", "); | |||
response = response + String(EEPROMr.base() - i); | |||
} | |||
return response; | |||
} | |||
#if TERMINAL_SUPPORT | |||
void _eepromInitCommands() { | |||
settingsRegisterCommand(F("EEPROM.DUMP"), [](Embedis* e) { | |||
EEPROMr.dump(settingsSerial()); | |||
DEBUG_MSG_P(PSTR("\n+OK\n")); | |||
}); | |||
settingsRegisterCommand(F("FLASH.DUMP"), [](Embedis* e) { | |||
if (e->argc < 2) { | |||
DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n")); | |||
return; | |||
} | |||
uint32_t sector = String(e->argv[1]).toInt(); | |||
uint32_t max = ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE; | |||
if (sector >= max) { | |||
DEBUG_MSG_P(PSTR("-ERROR: Sector out of range\n")); | |||
return; | |||
} | |||
EEPROMr.dump(settingsSerial(), sector); | |||
DEBUG_MSG_P(PSTR("\n+OK\n")); | |||
}); | |||
} | |||
#endif | |||
// ----------------------------------------------------------------------------- | |||
void eepromSetup() { | |||
#ifdef EEPROM_ROTATE_SECTORS | |||
EEPROMr.size(EEPROM_ROTATE_SECTORS); | |||
#else | |||
// If the memory layout has more than one sector reserved use those, | |||
// otherwise calculate pool size based on memory size. | |||
if (EEPROMr.size() == 1) { | |||
if (EEPROMr.last() > 1000) { // 4Mb boards | |||
EEPROMr.size(4); | |||
} else if (EEPROMr.last() > 250) { // 1Mb boards | |||
EEPROMr.size(2); | |||
} | |||
} | |||
#endif | |||
EEPROMr.offset(EEPROM_ROTATE_DATA); | |||
EEPROMr.begin(EEPROM_SIZE); | |||
#if TERMINAL_SUPPORT | |||
_eepromInitCommands(); | |||
#endif | |||
} |
@ -0,0 +1,636 @@ | |||
/** | |||
* This code is available at | |||
* http://www.mindspring.com/~pfilandr/C/fs_math/ | |||
* and it is believed to be public domain. | |||
*/ | |||
/* BEGIN fs_math.c */ | |||
#include "fs_math.h" | |||
#include <float.h> | |||
/* | |||
** pi == (atan(1.0 / 3) + atan(1.0 / 2)) * 4 | |||
*/ | |||
static double fs_pi(void); | |||
static long double fs_pil(void); | |||
double fs_sqrt(double x) | |||
{ | |||
int n; | |||
double a, b; | |||
if (x > 0 && DBL_MAX >= x) { | |||
for (n = 0; x > 2; x /= 4) { | |||
++n; | |||
} | |||
while (0.5 > x) { | |||
--n; | |||
x *= 4; | |||
} | |||
a = x; | |||
b = (1 + x) / 2; | |||
do { | |||
x = b; | |||
b = (a / x + x) / 2; | |||
} while (x > b); | |||
while (n > 0) { | |||
x *= 2; | |||
--n; | |||
} | |||
while (0 > n) { | |||
x /= 2; | |||
++n; | |||
} | |||
} else { | |||
if (x != 0) { | |||
x = DBL_MAX; | |||
} | |||
} | |||
return x; | |||
} | |||
double fs_log(double x) | |||
{ | |||
int n; | |||
double a, b, c, epsilon; | |||
static double A, B, C; | |||
static int initialized; | |||
if (x > 0 && DBL_MAX >= x) { | |||
if (!initialized) { | |||
initialized = 1; | |||
A = fs_sqrt(2); | |||
B = A / 2; | |||
C = fs_log(A); | |||
} | |||
for (n = 0; x > A; x /= 2) { | |||
++n; | |||
} | |||
while (B > x) { | |||
--n; | |||
x *= 2; | |||
} | |||
a = (x - 1) / (x + 1); | |||
x = C * n + a; | |||
c = a * a; | |||
n = 1; | |||
epsilon = DBL_EPSILON * x; | |||
if (0 > a) { | |||
if (epsilon > 0) { | |||
epsilon = -epsilon; | |||
} | |||
do { | |||
n += 2; | |||
a *= c; | |||
b = a / n; | |||
x += b; | |||
} while (epsilon > b); | |||
} else { | |||
if (0 > epsilon) { | |||
epsilon = -epsilon; | |||
} | |||
do { | |||
n += 2; | |||
a *= c; | |||
b = a / n; | |||
x += b; | |||
} while (b > epsilon); | |||
} | |||
x *= 2; | |||
} else { | |||
x = -DBL_MAX; | |||
} | |||
return x; | |||
} | |||
double fs_log10(double x) | |||
{ | |||
static double log_10; | |||
static int initialized; | |||
if (!initialized) { | |||
initialized = 1; | |||
log_10 = fs_log(10); | |||
} | |||
return x > 0 && DBL_MAX >= x ? fs_log(x) / log_10 : fs_log(x); | |||
} | |||
double fs_exp(double x) | |||
{ | |||
unsigned n, square; | |||
double b, e; | |||
static double x_max, x_min, epsilon; | |||
static int initialized; | |||
if (!initialized) { | |||
initialized = 1; | |||
x_max = fs_log(DBL_MAX); | |||
x_min = fs_log(DBL_MIN); | |||
epsilon = DBL_EPSILON / 4; | |||
} | |||
if (x_max >= x && x >= x_min) { | |||
for (square = 0; x > 1; x /= 2) { | |||
++square; | |||
} | |||
while (-1 > x) { | |||
++square; | |||
x /= 2; | |||
} | |||
e = b = n = 1; | |||
do { | |||
b /= n++; | |||
b *= x; | |||
e += b; | |||
b /= n++; | |||
b *= x; | |||
e += b; | |||
} while (b > epsilon); | |||
while (square-- != 0) { | |||
e *= e; | |||
} | |||
} else { | |||
e = x > 0 ? DBL_MAX : 0; | |||
} | |||
return e; | |||
} | |||
double fs_modf(double value, double *iptr) | |||
{ | |||
double a, b; | |||
const double c = value; | |||
if (0 > c) { | |||
value = -value; | |||
} | |||
if (DBL_MAX >= value) { | |||
for (*iptr = 0; value >= 1; value -= b) { | |||
a = value / 2; | |||
b = 1; | |||
while (a >= b) { | |||
b *= 2; | |||
} | |||
*iptr += b; | |||
} | |||
} else { | |||
*iptr = value; | |||
value = 0; | |||
} | |||
if (0 > c) { | |||
*iptr = -*iptr; | |||
value = -value; | |||
} | |||
return value; | |||
} | |||
double fs_fmod(double x, double y) | |||
{ | |||
double a, b; | |||
const double c = x; | |||
if (0 > c) { | |||
x = -x; | |||
} | |||
if (0 > y) { | |||
y = -y; | |||
} | |||
if (y != 0 && DBL_MAX >= y && DBL_MAX >= x) { | |||
while (x >= y) { | |||
a = x / 2; | |||
b = y; | |||
while (a >= b) { | |||
b *= 2; | |||
} | |||
x -= b; | |||
} | |||
} else { | |||
x = 0; | |||
} | |||
return 0 > c ? -x : x; | |||
} | |||
double fs_pow(double x, double y) | |||
{ | |||
double p = 0; | |||
if (0 > x && fs_fmod(y, 1) == 0) { | |||
if (fs_fmod(y, 2) == 0) { | |||
p = fs_exp(fs_log(-x) * y); | |||
} else { | |||
p = -fs_exp(fs_log(-x) * y); | |||
} | |||
} else { | |||
if (x != 0 || 0 >= y) { | |||
p = fs_exp(fs_log( x) * y); | |||
} | |||
} | |||
return p; | |||
} | |||
static double fs_pi(void) | |||
{ | |||
unsigned n; | |||
double a, b, epsilon; | |||
static double p; | |||
static int initialized; | |||
if (!initialized) { | |||
initialized = 1; | |||
epsilon = DBL_EPSILON / 4; | |||
n = 1; | |||
a = 3; | |||
do { | |||
a /= 9; | |||
b = a / n; | |||
n += 2; | |||
a /= 9; | |||
b -= a / n; | |||
n += 2; | |||
p += b; | |||
} while (b > epsilon); | |||
epsilon = DBL_EPSILON / 2; | |||
n = 1; | |||
a = 2; | |||
do { | |||
a /= 4; | |||
b = a / n; | |||
n += 2; | |||
a /= 4; | |||
b -= a / n; | |||
n += 2; | |||
p += b; | |||
} while (b > epsilon); | |||
p *= 4; | |||
} | |||
return p; | |||
} | |||
double fs_cos(double x) | |||
{ | |||
unsigned n; | |||
int negative, sine; | |||
double a, b, c; | |||
static double pi, two_pi, half_pi, third_pi, epsilon; | |||
static int initialized; | |||
if (0 > x) { | |||
x = -x; | |||
} | |||
if (DBL_MAX >= x) { | |||
if (!initialized) { | |||
initialized = 1; | |||
pi = fs_pi(); | |||
two_pi = 2 * pi; | |||
half_pi = pi / 2; | |||
third_pi = pi / 3; | |||
epsilon = DBL_EPSILON / 2; | |||
} | |||
if (x > two_pi) { | |||
x = fs_fmod(x, two_pi); | |||
} | |||
if (x > pi) { | |||
x = two_pi - x; | |||
} | |||
if (x > half_pi) { | |||
x = pi - x; | |||
negative = 1; | |||
} else { | |||
negative = 0; | |||
} | |||
if (x > third_pi) { | |||
x = half_pi - x; | |||
sine = 1; | |||
} else { | |||
sine = 0; | |||
} | |||
c = x * x; | |||
x = n = 0; | |||
a = 1; | |||
do { | |||
b = a; | |||
a *= c; | |||
a /= ++n; | |||
a /= ++n; | |||
b -= a; | |||
a *= c; | |||
a /= ++n; | |||
a /= ++n; | |||
x += b; | |||
} while (b > epsilon); | |||
if (sine) { | |||
x = fs_sqrt((1 - x) * (1 + x)); | |||
} | |||
if (negative) { | |||
x = -x; | |||
} | |||
} else { | |||
x = -DBL_MAX; | |||
} | |||
return x; | |||
} | |||
double fs_log2(double x) | |||
{ | |||
static double log_2; | |||
static int initialized; | |||
if (!initialized) { | |||
initialized = 1; | |||
log_2 = fs_log(2); | |||
} | |||
return x > 0 && DBL_MAX >= x ? fs_log(x) / log_2 : fs_log(x); | |||
} | |||
double fs_exp2(double x) | |||
{ | |||
static double log_2; | |||
static int initialized; | |||
if (!initialized) { | |||
initialized = 1; | |||
log_2 = fs_log(2); | |||
} | |||
return fs_exp(x * log_2); | |||
} | |||
long double fs_powl(long double x, long double y) | |||
{ | |||
long double p; | |||
if (0 > x && fs_fmodl(y, 1) == 0) { | |||
if (fs_fmodl(y, 2) == 0) { | |||
p = fs_expl(fs_logl(-x) * y); | |||
} else { | |||
p = -fs_expl(fs_logl(-x) * y); | |||
} | |||
} else { | |||
if (x != 0 || 0 >= y) { | |||
p = fs_expl(fs_logl( x) * y); | |||
} else { | |||
p = 0; | |||
} | |||
} | |||
return p; | |||
} | |||
long double fs_sqrtl(long double x) | |||
{ | |||
long int n; | |||
long double a, b; | |||
if (x > 0 && LDBL_MAX >= x) { | |||
for (n = 0; x > 2; x /= 4) { | |||
++n; | |||
} | |||
while (0.5 > x) { | |||
--n; | |||
x *= 4; | |||
} | |||
a = x; | |||
b = (1 + x) / 2; | |||
do { | |||
x = b; | |||
b = (a / x + x) / 2; | |||
} while (x > b); | |||
while (n > 0) { | |||
x *= 2; | |||
--n; | |||
} | |||
while (0 > n) { | |||
x /= 2; | |||
++n; | |||
} | |||
} else { | |||
if (x != 0) { | |||
x = LDBL_MAX; | |||
} | |||
} | |||
return x; | |||
} | |||
long double fs_logl(long double x) | |||
{ | |||
long int n; | |||
long double a, b, c, epsilon; | |||
static long double A, B, C; | |||
static int initialized; | |||
if (x > 0 && LDBL_MAX >= x) { | |||
if (!initialized) { | |||
initialized = 1; | |||
B = 1.5; | |||
do { | |||
A = B; | |||
B = 1 / A + A / 2; | |||
} while (A > B); | |||
B /= 2; | |||
C = fs_logl(A); | |||
} | |||
for (n = 0; x > A; x /= 2) { | |||
++n; | |||
} | |||
while (B > x) { | |||
--n; | |||
x *= 2; | |||
} | |||
a = (x - 1) / (x + 1); | |||
x = C * n + a; | |||
c = a * a; | |||
n = 1; | |||
epsilon = LDBL_EPSILON * x; | |||
if (0 > a) { | |||
if (epsilon > 0) { | |||
epsilon = -epsilon; | |||
} | |||
do { | |||
n += 2; | |||
a *= c; | |||
b = a / n; | |||
x += b; | |||
} while (epsilon > b); | |||
} else { | |||
if (0 > epsilon) { | |||
epsilon = -epsilon; | |||
} | |||
do { | |||
n += 2; | |||
a *= c; | |||
b = a / n; | |||
x += b; | |||
} while (b > epsilon); | |||
} | |||
x *= 2; | |||
} else { | |||
x = -LDBL_MAX; | |||
} | |||
return x; | |||
} | |||
long double fs_expl(long double x) | |||
{ | |||
long unsigned n, square; | |||
long double b, e; | |||
static long double x_max, x_min, epsilon; | |||
static int initialized; | |||
if (!initialized) { | |||
initialized = 1; | |||
x_max = fs_logl(LDBL_MAX); | |||
x_min = fs_logl(LDBL_MIN); | |||
epsilon = LDBL_EPSILON / 4; | |||
} | |||
if (x_max >= x && x >= x_min) { | |||
for (square = 0; x > 1; x /= 2) { | |||
++square; | |||
} | |||
while (-1 > x) { | |||
++square; | |||
x /= 2; | |||
} | |||
e = b = n = 1; | |||
do { | |||
b /= n++; | |||
b *= x; | |||
e += b; | |||
b /= n++; | |||
b *= x; | |||
e += b; | |||
} while (b > epsilon); | |||
while (square-- != 0) { | |||
e *= e; | |||
} | |||
} else { | |||
e = x > 0 ? LDBL_MAX : 0; | |||
} | |||
return e; | |||
} | |||
static long double fs_pil(void) | |||
{ | |||
long unsigned n; | |||
long double a, b, epsilon; | |||
static long double p; | |||
static int initialized; | |||
if (!initialized) { | |||
initialized = 1; | |||
epsilon = LDBL_EPSILON / 4; | |||
n = 1; | |||
a = 3; | |||
do { | |||
a /= 9; | |||
b = a / n; | |||
n += 2; | |||
a /= 9; | |||
b -= a / n; | |||
n += 2; | |||
p += b; | |||
} while (b > epsilon); | |||
epsilon = LDBL_EPSILON / 2; | |||
n = 1; | |||
a = 2; | |||
do { | |||
a /= 4; | |||
b = a / n; | |||
n += 2; | |||
a /= 4; | |||
b -= a / n; | |||
n += 2; | |||
p += b; | |||
} while (b > epsilon); | |||
p *= 4; | |||
} | |||
return p; | |||
} | |||
long double fs_cosl(long double x) | |||
{ | |||
long unsigned n; | |||
int negative, sine; | |||
long double a, b, c; | |||
static long double pi, two_pi, half_pi, third_pi, epsilon; | |||
static int initialized; | |||
if (0 > x) { | |||
x = -x; | |||
} | |||
if (LDBL_MAX >= x) { | |||
if (!initialized) { | |||
initialized = 1; | |||
pi = fs_pil(); | |||
two_pi = 2 * pi; | |||
half_pi = pi / 2; | |||
third_pi = pi / 3; | |||
epsilon = LDBL_EPSILON / 2; | |||
} | |||
if (x > two_pi) { | |||
x = fs_fmodl(x, two_pi); | |||
} | |||
if (x > pi) { | |||
x = two_pi - x; | |||
} | |||
if (x > half_pi) { | |||
x = pi - x; | |||
negative = 1; | |||
} else { | |||
negative = 0; | |||
} | |||
if (x > third_pi) { | |||
x = half_pi - x; | |||
sine = 1; | |||
} else { | |||
sine = 0; | |||
} | |||
c = x * x; | |||
x = n = 0; | |||
a = 1; | |||
do { | |||
b = a; | |||
a *= c; | |||
a /= ++n; | |||
a /= ++n; | |||
b -= a; | |||
a *= c; | |||
a /= ++n; | |||
a /= ++n; | |||
x += b; | |||
} while (b > epsilon); | |||
if (sine) { | |||
x = fs_sqrtl((1 - x) * (1 + x)); | |||
} | |||
if (negative) { | |||
x = -x; | |||
} | |||
} else { | |||
x = -LDBL_MAX; | |||
} | |||
return x; | |||
} | |||
long double fs_fmodl(long double x, long double y) | |||
{ | |||
long double a, b; | |||
const long double c = x; | |||
if (0 > c) { | |||
x = -x; | |||
} | |||
if (0 > y) { | |||
y = -y; | |||
} | |||
if (y != 0 && LDBL_MAX >= y && LDBL_MAX >= x) { | |||
while (x >= y) { | |||
a = x / 2; | |||
b = y; | |||
while (a >= b) { | |||
b *= 2; | |||
} | |||
x -= b; | |||
} | |||
} else { | |||
x = 0; | |||
} | |||
return 0 > c ? -x : x; | |||
} | |||
/* END fs_math.c */ |
@ -0,0 +1,116 @@ | |||
/** | |||
* This code is available at | |||
* http://www.mindspring.com/~pfilandr/C/fs_math/ | |||
* and it is believed to be public domain. | |||
*/ | |||
/* BEGIN fs_math.h */ | |||
/* | |||
** Portable freestanding code. | |||
*/ | |||
#ifndef H_FS_MATH_H | |||
#define H_FS_MATH_H | |||
double fs_sqrt(double x); | |||
double fs_log(double x); | |||
double fs_log10(double x); | |||
/* | |||
** exp(x) = 1 + x + x^2/2! + x^3/3! + ... | |||
*/ | |||
double fs_exp(double x); | |||
double fs_modf(double value, double *iptr); | |||
double fs_fmod(double x, double y); | |||
double fs_pow(double x, double y); | |||
double fs_cos(double x); | |||
/* | |||
** C99 | |||
*/ | |||
double fs_log2(double x); | |||
double fs_exp2(double x); | |||
long double fs_powl(long double x, long double y); | |||
long double fs_sqrtl(long double x); | |||
long double fs_logl(long double x); | |||
long double fs_expl(long double x); | |||
long double fs_cosl(long double x); | |||
long double fs_fmodl(long double x, long double y); | |||
#endif | |||
/* END fs_math.h */ | |||
#if 0 | |||
/* | |||
> > Anybody know where I can get some source code for a | |||
> > reasonably fast double | |||
> > precision square root algorithm in C. | |||
> > I'm looking for one that is not IEEE | |||
> > compliant as I am running on a Z/OS mainframe. | |||
> > | |||
> > I would love to use the standard library but | |||
> > unfortunatly I'm using a | |||
> > stripped down version of C that looses the the runtime library | |||
> > (we have to write our own). | |||
> | |||
> long double Ssqrt(long double x) | |||
> { | |||
> long double a, b; | |||
> size_t c; | |||
size_t is a bug here. | |||
c needs to be a signed type: | |||
long c; | |||
> if (x > 0) { | |||
> c = 0; | |||
> while (x > 4) { | |||
> x /= 4; | |||
> ++c; | |||
> } | |||
> while (1.0 / 4 > x) { | |||
> x *= 4; | |||
> --c; | |||
> } | |||
> a = x; | |||
> b = ((4 > a) + a) / 2; | |||
Not a bug, but should be: | |||
b = (1 + a) / 2; | |||
> do { | |||
> x = b; | |||
> b = (a / x + x) / 2; | |||
> } while (x > b); | |||
> if (c > 0) { | |||
The above line is why c needs to be a signed type, | |||
otherwise the decremented values of c, are greater than zero, | |||
and the function won't work if the initial value of x | |||
is less than 0.25 | |||
> while (c--) { | |||
> x *= 2; | |||
> } | |||
> } else { | |||
> while (c++) { | |||
> x /= 2; | |||
> } | |||
> } | |||
> } | |||
> return x; | |||
> } | |||
> | |||
> > | |||
> > That algorithm was actually 4 times slower | |||
> > then the one below, and more | |||
> > code. It was accurate though. | |||
> > | |||
> | |||
> Sorry Pete, I wasn't looking very carefully. | |||
> When I converted your function | |||
> to double precision it's was much quicker, the best I've seen yet. | |||
*/ | |||
#endif |
@ -0,0 +1,298 @@ | |||
// ----------------------------------------------------------------------------- | |||
// Geiger Sensor based on Event Counter Sensor | |||
// Copyright (C) 2018 by Sven Kopetzki <skopetzki at web dot de> | |||
// Documentation: https://github.com/Trickx/espurna/wiki/Geiger-counter | |||
// ----------------------------------------------------------------------------- | |||
#if SENSOR_SUPPORT && GEIGER_SUPPORT | |||
#pragma once | |||
#include "Arduino.h" | |||
#include "BaseSensor.h" | |||
class GeigerSensor : public BaseSensor { | |||
public: | |||
// --------------------------------------------------------------------- | |||
// Public | |||
// --------------------------------------------------------------------- | |||
GeigerSensor() : BaseSensor() { | |||
_count = 2; | |||
_sensor_id = SENSOR_GEIGER_ID; | |||
} | |||
~GeigerSensor() { | |||
_enableInterrupts(false); | |||
} | |||
// --------------------------------------------------------------------- | |||
void setGPIO(unsigned char gpio) { | |||
_gpio = gpio; | |||
} | |||
void setMode(unsigned char mode) { | |||
_mode = mode; | |||
} | |||
void setInterruptMode(unsigned char mode) { | |||
_interrupt_mode = mode; | |||
} | |||
void setDebounceTime(unsigned long debounce) { | |||
_debounce = debounce; | |||
} | |||
void setCPM2SievertFactor(unsigned int cpm2sievert) { | |||
_cpm2sievert = cpm2sievert; | |||
} | |||
// --------------------------------------------------------------------- | |||
unsigned char getGPIO() { | |||
return _gpio; | |||
} | |||
unsigned char getMode() { | |||
return _mode; | |||
} | |||
unsigned char getInterruptMode() { | |||
return _interrupt_mode; | |||
} | |||
unsigned long getDebounceTime() { | |||
return _debounce; | |||
} | |||
unsigned long getCPM2SievertFactor() { | |||
return _cpm2sievert; | |||
} | |||
// --------------------------------------------------------------------- | |||
// Sensors API | |||
// --------------------------------------------------------------------- | |||
// Initialization method, must be idempotent | |||
// Defined outside the class body | |||
void begin() { | |||
pinMode(_gpio, _mode); | |||
_enableInterrupts(true); | |||
_ready = true; | |||
} | |||
// Descriptive name of the sensor | |||
String description() { | |||
char buffer[20]; | |||
snprintf(buffer, sizeof(buffer), "µSv/h @ GPIO%d", _gpio); | |||
return String(buffer); | |||
} | |||
// Descriptive name of the slot # index | |||
String slot(unsigned char index) { | |||
char buffer[30]; | |||
unsigned char i=0; | |||
#if GEIGER_REPORT_CPM | |||
if (index == i++) { | |||
snprintf(buffer, sizeof(buffer), "Counts per Minute @ GPIO%d", _gpio); | |||
return String(buffer); | |||
} | |||
#endif | |||
#if GEIGER_REPORT_SIEVERTS | |||
if (index == i++) { | |||
snprintf(buffer, sizeof(buffer), "CPM / %d = µSv/h", _cpm2sievert); | |||
return String(buffer); | |||
} | |||
#endif | |||
snprintf(buffer, sizeof(buffer), "Events @ GPIO%d", _gpio); | |||
return String(buffer); | |||
}; | |||
// Address of the sensor (it could be the GPIO or I2C address) | |||
String address(unsigned char index) { | |||
return String(_gpio); | |||
} | |||
// Type for slot # index | |||
unsigned char type(unsigned char index) { | |||
unsigned char i=0; | |||
#if GEIGER_REPORT_CPM | |||
if (index == i++) return MAGNITUDE_GEIGER_CPM; | |||
#endif | |||
#if GEIGER_REPORT_SIEVERTS | |||
if (index == i++) return MAGNITUDE_GEIGER_SIEVERT; | |||
#endif | |||
return MAGNITUDE_NONE; | |||
} | |||
// Current value for slot # index | |||
double value(unsigned char index) { | |||
unsigned char i=0; | |||
#if GEIGER_REPORT_CPM | |||
if (index == i++) { | |||
unsigned long _period_begin = _lastreport_cpm; | |||
_lastreport_cpm = millis(); | |||
double value = _events * 60000; | |||
value = value / (_lastreport_cpm-_period_begin); | |||
#if SENSOR_DEBUG | |||
char data[128]; char buffer[10]; | |||
dtostrf(value, 1-sizeof(buffer), 4, buffer); | |||
snprintf(data, sizeof(data), "Ticks: %u | Interval: %u | CPM: %s", _ticks, (_lastreport_cpm-_period_begin), buffer); | |||
DEBUG_MSG("[GEIGER] %s\n", data); | |||
#endif | |||
_events = 0; | |||
return value; | |||
} | |||
#endif | |||
#if GEIGER_REPORT_SIEVERTS | |||
if (index == i++) { | |||
unsigned long _period_begin = _lastreport_sv; | |||
_lastreport_sv = millis(); | |||
double value = _ticks * 60000 / _cpm2sievert; | |||
value = value / (_lastreport_sv-_period_begin); | |||
#if SENSOR_DEBUG | |||
char data[128]; char buffer[10]; | |||
dtostrf(value, 1-sizeof(buffer), 4, buffer); | |||
snprintf(data, sizeof(data), "Ticks: %u | Interval: %u | µSievert: %s", _ticks, (_lastreport_sv-_period_begin), buffer); | |||
DEBUG_MSG("[GEIGER] %s\n", data); | |||
#endif | |||
_ticks = 0; | |||
return value; | |||
} | |||
#endif | |||
return 0; | |||
} | |||
// Handle interrupt calls | |||
void handleInterrupt(unsigned char gpio) { | |||
(void) gpio; | |||
static unsigned long last = 0; | |||
if (millis() - last > _debounce) { | |||
_events = _events + 1; | |||
_ticks = _ticks + 1; | |||
last = millis(); | |||
} | |||
} | |||
protected: | |||
// --------------------------------------------------------------------- | |||
// Interrupt management | |||
// --------------------------------------------------------------------- | |||
void _attach(GeigerSensor * instance, unsigned char gpio, unsigned char mode); | |||
void _detach(unsigned char gpio); | |||
void _enableInterrupts(bool value) { | |||
static unsigned char _interrupt_gpio = GPIO_NONE; | |||
if (value) { | |||
if (_interrupt_gpio != GPIO_NONE) _detach(_interrupt_gpio); | |||
_attach(this, _gpio, _interrupt_mode); | |||
_interrupt_gpio = _gpio; | |||
} else if (_interrupt_gpio != GPIO_NONE) { | |||
_detach(_interrupt_gpio); | |||
_interrupt_gpio = GPIO_NONE; | |||
} | |||
} | |||
// --------------------------------------------------------------------- | |||
// Protected | |||
// --------------------------------------------------------------------- | |||
volatile unsigned long _events = 0; | |||
volatile unsigned long _ticks = 0; | |||
unsigned long _debounce = GEIGER_DEBOUNCE; | |||
unsigned int _cpm2sievert = GEIGER_CPM2SIEVERT; | |||
unsigned char _gpio; | |||
unsigned char _mode; | |||
unsigned char _interrupt_mode; | |||
// Added for µSievert calculations | |||
unsigned long _lastreport_cpm = millis(); | |||
unsigned long _lastreport_sv = _lastreport_cpm; | |||
}; | |||
// ----------------------------------------------------------------------------- | |||
// Interrupt helpers | |||
// ----------------------------------------------------------------------------- | |||
GeigerSensor * _geiger_sensor_instance[10] = {NULL}; | |||
void ICACHE_RAM_ATTR _geiger_sensor_isr(unsigned char gpio) { | |||
unsigned char index = gpio > 5 ? gpio-6 : gpio; | |||
if (_geiger_sensor_instance[index]) { | |||
_geiger_sensor_instance[index]->handleInterrupt(gpio); | |||
} | |||
} | |||
void ICACHE_RAM_ATTR _geiger_sensor_isr_0() { | |||
_geiger_sensor_isr(0); | |||
} | |||
void ICACHE_RAM_ATTR _geiger_sensor_isr_1() { | |||
_geiger_sensor_isr(1); | |||
} | |||
void ICACHE_RAM_ATTR _geiger_sensor_isr_2() { | |||
_geiger_sensor_isr(2); | |||
} | |||
void ICACHE_RAM_ATTR _geiger_sensor_isr_3() { | |||
_geiger_sensor_isr(3); | |||
} | |||
void ICACHE_RAM_ATTR _geiger_sensor_isr_4() { | |||
_geiger_sensor_isr(4); | |||
} | |||
void ICACHE_RAM_ATTR _geiger_sensor_isr_5() { | |||
_geiger_sensor_isr(5); | |||
} | |||
void ICACHE_RAM_ATTR _geiger_sensor_isr_12() { | |||
_geiger_sensor_isr(12); | |||
} | |||
void ICACHE_RAM_ATTR _geiger_sensor_isr_13() { | |||
_geiger_sensor_isr(13); | |||
} | |||
void ICACHE_RAM_ATTR _geiger_sensor_isr_14() { | |||
_geiger_sensor_isr(14); | |||
} | |||
void ICACHE_RAM_ATTR _geiger_sensor_isr_15() { | |||
_geiger_sensor_isr(15); | |||
} | |||
static void (*_geiger_sensor_isr_list[10])() = { | |||
_geiger_sensor_isr_0, _geiger_sensor_isr_1, _geiger_sensor_isr_2, | |||
_geiger_sensor_isr_3, _geiger_sensor_isr_4, _geiger_sensor_isr_5, | |||
_geiger_sensor_isr_12, _geiger_sensor_isr_13, _geiger_sensor_isr_14, | |||
_geiger_sensor_isr_15 | |||
}; | |||
void GeigerSensor::_attach(GeigerSensor * instance, unsigned char gpio, unsigned char mode) { | |||
if (!gpioValid(gpio)) return; | |||
_detach(gpio); | |||
unsigned char index = gpio > 5 ? gpio-6 : gpio; | |||
_geiger_sensor_instance[index] = instance; | |||
attachInterrupt(gpio, _geiger_sensor_isr_list[index], mode); | |||
#if SENSOR_DEBUG | |||
DEBUG_MSG_P(PSTR("[GEIGER] GPIO%d interrupt attached to %s\n"), gpio, instance->description().c_str()); | |||
#endif | |||
} | |||
void GeigerSensor::_detach(unsigned char gpio) { | |||
if (!gpioValid(gpio)) return; | |||
unsigned char index = gpio > 5 ? gpio-6 : gpio; | |||
if (_geiger_sensor_instance[index]) { | |||
detachInterrupt(gpio); | |||
#if SENSOR_DEBUG | |||
DEBUG_MSG_P(PSTR("[GEIGER] GPIO%d interrupt detached from %s\n"), gpio, _geiger_sensor_instance[index]->description().c_str()); | |||
#endif | |||
_geiger_sensor_instance[index] = NULL; | |||
} | |||
} | |||
#endif // SENSOR_SUPPORT && GEIGER_SUPPORT |
@ -0,0 +1,57 @@ | |||
#!/bin/bash | |||
# ------------------------------------------------------------------------------ | |||
# CONFIGURATION | |||
# ------------------------------------------------------------------------------ | |||
ENVIRONMENT="wemos-d1mini-relayshield" | |||
READELF="xtensa-lx106-elf-readelf" | |||
NUMBER=20 | |||
# ------------------------------------------------------------------------------ | |||
# END CONFIGURATION - DO NOT EDIT FURTHER | |||
# ------------------------------------------------------------------------------ | |||
# remove default trace file | |||
rm -rf $FILE | |||
function help { | |||
echo | |||
echo "Syntax: $0 [-e <environment>] [-n <number>]" | |||
echo | |||
} | |||
# get environment from command line | |||
while [[ $# -gt 1 ]]; do | |||
key="$1" | |||
case $key in | |||
-e) | |||
ENVIRONMENT="$2" | |||
shift | |||
;; | |||
-n) | |||
NUMBER="$2" | |||
shift | |||
;; | |||
esac | |||
shift # past argument or value | |||
done | |||
# check environment folder | |||
if [ $ENVIRONMENT == "" ]; then | |||
echo "No environment defined" | |||
help | |||
exit 1 | |||
fi | |||
ELF=.pioenvs/$ENVIRONMENT/firmware.elf | |||
if [ ! -f $ELF ]; then | |||
echo "Could not find ELF file for the selected environment: $ELF" | |||
exit 2 | |||
fi | |||
$READELF -s $ELF | head -3 | tail -1 | |||
$READELF -s $ELF | sort -r -k3 -n | head -$NUMBER |