Browse Source

relay: rework mask handling to use generic u32<->string conversion

master
Maxim Prokhorov 5 years ago
parent
commit
e7fc5f337b
4 changed files with 113 additions and 72 deletions
  1. +34
    -0
      code/espurna/relay.h
  2. +41
    -29
      code/espurna/relay.ino
  3. +3
    -2
      code/espurna/utils.h
  4. +35
    -41
      code/espurna/utils.ino

+ 34
- 0
code/espurna/relay.h View File

@ -8,6 +8,9 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#pragma once #pragma once
#include <bitset>
#include "utils.h"
constexpr size_t RELAYS_MAX = 32; constexpr size_t RELAYS_MAX = 32;
enum class RelayStatus : unsigned char { enum class RelayStatus : unsigned char {
@ -17,6 +20,37 @@ enum class RelayStatus : unsigned char {
UNKNOWN = 0xFF UNKNOWN = 0xFF
}; };
struct RelayMask {
explicit RelayMask(const String& string) :
as_string(string),
as_u32(u32fromString(string))
{}
explicit RelayMask(String&& string) :
as_string(std::move(string)),
as_u32(u32fromString(as_string))
{}
explicit RelayMask(uint32_t value) :
as_string(std::move(u32toString(value, 2))),
as_u32(value)
{}
explicit RelayMask(std::bitset<RELAYS_MAX> bitset) :
RelayMask(bitset.to_ulong())
{}
RelayMask(String&& string, uint32_t value) :
as_string(std::move(string)),
as_u32(value)
{}
const String as_string;
uint32_t as_u32;
};
RelayStatus relayParsePayload(const char * payload); RelayStatus relayParsePayload(const char * payload);
bool relayStatus(unsigned char id, bool status, bool report, bool group_report); bool relayStatus(unsigned char id, bool status, bool report, bool group_report);


+ 41
- 29
code/espurna/relay.ino View File

@ -384,26 +384,42 @@ void setSpeed(unsigned char speed) {
// RELAY // RELAY
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void _relayMaskRtcmem(uint32_t mask) {
// State persistance persistance
RelayMask INLINE _relayMaskRtcmem() {
return RelayMask(Rtcmem->relay);
}
void INLINE _relayMaskRtcmem(uint32_t mask) {
Rtcmem->relay = mask; Rtcmem->relay = mask;
} }
uint32_t _relayMaskRtcmem() {
return Rtcmem->relay;
void INLINE _relayMaskRtcmem(const RelayMask& mask) {
_relayMaskRtcmem(mask.as_u32);
}
void INLINE _relayMaskRtcmem(const std::bitset<RELAYS_MAX>& bitset) {
_relayMaskRtcmem(bitset.to_ulong());
}
RelayMask INLINE _relayMaskSettings() {
return RelayMask(getSetting("relayBootMask"));
} }
void _relayMaskSettings(const String& string) {
setSetting("relayBootMask", string);
void INLINE _relayMaskSettings(uint32_t mask) {
setSetting("relayBootMask", u32toString(mask, 2));
} }
void _relayMaskSettings(uint32_t mask) {
_relayMaskSettings(bitsetToString(mask));
void INLINE _relayMaskSettings(const RelayMask& mask) {
setSetting("relayBootMask", mask.as_string);
} }
uint32_t _relayMaskSettings() {
return bitsetFromString(getSetting("relayBootMask"));
void INLINE _relayMaskSettings(const std::bitset<RELAYS_MAX>& bitset) {
_relayMaskSettings(bitset.to_ulong());
} }
// Pulse timers (timer after ON or OFF event)
void relayPulse(unsigned char id) { void relayPulse(unsigned char id) {
_relays[id].pulseTicker.detach(); _relays[id].pulseTicker.detach();
@ -426,6 +442,8 @@ void relayPulse(unsigned char id) {
} }
// General relay status control
bool relayStatus(unsigned char id, bool status, bool report, bool group_report) { bool relayStatus(unsigned char id, bool status, bool report, bool group_report) {
if (id >= _relays.size()) return false; if (id >= _relays.size()) return false;
@ -577,19 +595,18 @@ void relaySync(unsigned char id) {
void relaySave(bool eeprom) { void relaySave(bool eeprom) {
auto mask = std::bitset<RELAYS_MAX>(0);
const unsigned char count = constrain(relayCount(), 0, RELAYS_MAX); const unsigned char count = constrain(relayCount(), 0, RELAYS_MAX);
auto statuses = std::bitset<RELAYS_MAX>(0);
for (unsigned int id = 0; id < count; ++id) { for (unsigned int id = 0; id < count; ++id) {
mask.set(id, relayStatus(id));
statuses.set(id, relayStatus(id));
} }
const uint32_t mask_value = mask.to_ulong();
const String mask_string = bitsetToString(mask_value);
DEBUG_MSG_P(PSTR("[RELAY] Setting relay mask: %s\n"), mask_string.c_str());
const RelayMask mask(statuses);
DEBUG_MSG_P(PSTR("[RELAY] Setting relay mask: %s\n"), mask.as_string.c_str());
// Persist only to rtcmem, unless requested to save to the eeprom // Persist only to rtcmem, unless requested to save to the eeprom
_relayMaskRtcmem(mask_value);
_relayMaskRtcmem(mask);
// The 'eeprom' flag controls whether we are commiting this change or not. // The 'eeprom' flag controls whether we are commiting this change or not.
// It is useful to set it to 'false' if the relay change triggering the // It is useful to set it to 'false' if the relay change triggering the
@ -598,7 +615,7 @@ void relaySave(bool eeprom) {
// Nevertheless, we store the value in the EEPROM buffer so it will be written // Nevertheless, we store the value in the EEPROM buffer so it will be written
// on the next commit. // on the next commit.
if (eeprom) { if (eeprom) {
_relayMaskSettings(mask_string);
_relayMaskSettings(mask);
// We are actually enqueuing the commit so it will be // We are actually enqueuing the commit so it will be
// executed on the main loop, in case this is called from a system context callback // executed on the main loop, in case this is called from a system context callback
eepromCommit(); eepromCommit();
@ -686,18 +703,14 @@ void _relayBoot() {
_relayRecursive = true; _relayRecursive = true;
bool trigger_save = false; bool trigger_save = false;
uint32_t stored_mask = 0;
if (rtcmemStatus()) {
stored_mask = _relayMaskRtcmem();
} else {
stored_mask = _relayMaskSettings();
}
const auto stored_mask = rtcmemStatus()
? _relayMaskRtcmem()
: _relayMaskSettings();
const String string_mask(bitsetToString(stored_mask));
DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %s\n"), string_mask.c_str());
DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %s\n"), stored_mask.as_string.c_str());
auto mask = std::bitset<RELAYS_MAX>(stored_mask);
auto mask = std::bitset<RELAYS_MAX>(stored_mask.as_u32);
// Walk the relays // Walk the relays
unsigned char lock; unsigned char lock;
@ -747,12 +760,11 @@ void _relayBoot() {
} }
const auto mask_value = mask.to_ulong();
_relayMaskRtcmem(mask_value);
_relayMaskRtcmem(mask);
// Save if there is any relay in the RELAY_BOOT_TOGGLE mode // Save if there is any relay in the RELAY_BOOT_TOGGLE mode
if (trigger_save) { if (trigger_save) {
_relayMaskSettings(mask_value);
_relayMaskSettings(mask);
} }
_relayRecursive = false; _relayRecursive = false;


+ 3
- 2
code/espurna/utils.h View File

@ -52,5 +52,6 @@ void nice_delay(unsigned long ms);
double roundTo(double num, unsigned char positions); double roundTo(double num, unsigned char positions);
uint32_t bitsetFromString(const String& string);
String bitsetToString(uint32_t bitset);
uint32_t u32fromString(const String& string, int base);
uint32_t u32fromString(const String& string);
String u32toString(uint32_t bitset, int base);

+ 35
- 41
code/espurna/utils.ino View File

@ -134,22 +134,6 @@ bool haveRelaysOrSensors() {
return result; return result;
} }
// TODO: force getSetting return type to handle settings
uint32_t u32fromString(const String& string, int base = 10) {
const char *ptr = string.c_str();
char *value_endptr = nullptr;
// invalidate the whole string when invalid chars are detected
const auto value = strtoul(ptr, &value_endptr, base);
if (value_endptr == ptr || value_endptr[0] != '\0') {
return 0;
}
return value;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Heartbeat helper // Heartbeat helper
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -691,42 +675,52 @@ char* strnstr(const char* buffer, const char* token, size_t n) {
return nullptr; return nullptr;
} }
// Note:
// - when using standard base-2 literal syntax, parse that
// to keep backwards compatibility
// - otherwise, fallback to base-10 numbers
uint32_t bitsetFromString(const String& string) {
// TODO: force getSetting return type to handle settings
uint32_t u32fromString(const String& string, int base) {
const char *ptr = string.c_str();
char *value_endptr = nullptr;
// invalidate the whole string when invalid chars are detected
const auto value = strtoul(ptr, &value_endptr, base);
if (value_endptr == ptr || value_endptr[0] != '\0') {
return 0;
}
return value;
}
uint32_t u32fromString(const String& string) {
if (!string.length()) { if (!string.length()) {
return 0; return 0;
} }
if (string.startsWith("0b") && (string.length() > 2)) {
return u32fromString(string.substring(2), 2);
int base = 10;
if (string.length() > 2) {
if (string.startsWith("0b")) {
base = 2;
} else if (string.startsWith("0o")) {
base = 8;
} else if (string.startsWith("0x")) {
base = 16;
} else {
return 0;
}
return u32fromString(string.substring(2), base);
} }
return u32fromString(string);
return u32fromString(string, base);
} }
// Note:
// - bitset::to_string() will return std::string
// - itoa accepts int, so it will cut the sign bit
String bitsetToString(uint32_t value) {
String u32toString(uint32_t value, int base) {
String result; String result;
result.reserve(34);
result.reserve(32 + 2);
result += "0b"; result += "0b";
const uint32_t _value { value };
size_t bits = 0;
do {
value >>= 1;
bits++;
} while (value);
int bit = bits - 1;
do {
result += ((_value & (1 << bit)) ? '1' : '0');
} while (--bit >= 0);
char buffer[33] = {0};
ultoa(value, buffer, base);
result += buffer;
return result; return result;
} }

Loading…
Cancel
Save