addd ssd1306 lib
This commit is contained in:
186
P1_gateway_FW/lib/dsmr/util.h
Normal file
186
P1_gateway_FW/lib/dsmr/util.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* Arduino DSMR parser.
|
||||
*
|
||||
* This software is licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2015 Matthijs Kooijman <matthijs@stdin.nl>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Various utility functions
|
||||
*/
|
||||
|
||||
#ifndef DSMR_INCLUDE_UTIL_H
|
||||
#define DSMR_INCLUDE_UTIL_H
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
#define DSMR_PROGMEM
|
||||
#else
|
||||
#define DSMR_PROGMEM PROGMEM
|
||||
#endif
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
namespace dsmr {
|
||||
|
||||
/**
|
||||
* Small utility to get the length of an array at compiletime.
|
||||
*/
|
||||
template<typename T, unsigned int sz>
|
||||
inline unsigned int lengthof(const T (&)[sz]) { return sz; }
|
||||
|
||||
// Hack until https://github.com/arduino/Arduino/pull/1936 is merged.
|
||||
// This appends the given number of bytes from the given C string to the
|
||||
// given Arduino string, without requiring a trailing NUL.
|
||||
// Requires that there _is_ room for nul-termination
|
||||
static void concat_hack(String& s, const char *append, size_t n) {
|
||||
// Add null termination. Inefficient, but it works...
|
||||
char buf[n + 1];
|
||||
memcpy(buf, append, n);
|
||||
buf[n] = 0;
|
||||
s.concat(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* The ParseResult<T> class wraps the result of a parse function. The type
|
||||
* of the result is passed as a template parameter and can be void to
|
||||
* not return any result.
|
||||
*
|
||||
* A ParseResult can either:
|
||||
* - Return an error. In this case, err is set to an error message, ctx
|
||||
* is optionally set to where the error occurred. The result (if any)
|
||||
* and the next pointer are meaningless.
|
||||
* - Return succesfully. In this case, err and ctx are NULL, result
|
||||
* contains the result (if any) and next points one past the last
|
||||
* byte processed by the parser.
|
||||
*
|
||||
* The ParseResult class has some convenience functions:
|
||||
* - succeed(result): sets the result to the given value and returns
|
||||
* the ParseResult again.
|
||||
* - fail(err): Set the err member to the error message passed,
|
||||
* optionally sets the ctx and return the ParseResult again.
|
||||
* - until(next): Set the next member and return the ParseResult again.
|
||||
*
|
||||
* Furthermore, ParseResults can be implicitely converted to other
|
||||
* types. In this case, the error message, context and and next pointer are
|
||||
* conserved, the return value is reset to the default value for the
|
||||
* target type.
|
||||
*
|
||||
* Note that ctx points into the string being parsed, so it does not
|
||||
* need to be freed, lives as long as the original string and is
|
||||
* probably way longer that needed.
|
||||
*/
|
||||
|
||||
// Superclass for ParseResult so we can specialize for void without
|
||||
// having to duplicate all content
|
||||
template <typename P, typename T>
|
||||
struct _ParseResult {
|
||||
T result;
|
||||
|
||||
P& succeed(T& result) {
|
||||
this->result = result; return *static_cast<P*>(this);
|
||||
}
|
||||
P& succeed(T&& result) {
|
||||
this->result = result;
|
||||
return *static_cast<P*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
// partial specialization for void result
|
||||
template <typename P>
|
||||
struct _ParseResult<P, void> {
|
||||
};
|
||||
|
||||
// Actual ParseResult class
|
||||
template <typename T>
|
||||
struct ParseResult : public _ParseResult<ParseResult<T>, T> {
|
||||
const char *next = NULL;
|
||||
const __FlashStringHelper *err = NULL;
|
||||
const char *ctx = NULL;
|
||||
|
||||
ParseResult& fail(const __FlashStringHelper *err, const char* ctx = NULL) {
|
||||
this->err = err;
|
||||
this->ctx = ctx;
|
||||
return *this;
|
||||
}
|
||||
ParseResult& until(const char *next) {
|
||||
this->next = next;
|
||||
return *this;
|
||||
}
|
||||
ParseResult() = default;
|
||||
ParseResult(const ParseResult& other) = default;
|
||||
|
||||
template <typename T2>
|
||||
ParseResult(const ParseResult<T2>& other): next(other.next), err(other.err), ctx(other.ctx) { }
|
||||
|
||||
/**
|
||||
* Returns the error, including context in a fancy multi-line format.
|
||||
* The start and end passed are the first and one-past-the-end
|
||||
* characters in the total parsed string. These are needed to properly
|
||||
* limit the context output.
|
||||
*/
|
||||
String fullError(const char* start, const char* end) const {
|
||||
String res;
|
||||
if (this->ctx && start && end) {
|
||||
// Find the entire line surrounding the context
|
||||
const char *line_end = this->ctx;
|
||||
while(line_end < end && line_end[0] != '\r' && line_end[0] != '\n') ++line_end;
|
||||
const char *line_start = this->ctx;
|
||||
while(line_start > start && line_start[-1] != '\r' && line_start[-1] != '\n') --line_start;
|
||||
|
||||
// We can now predict the context string length, so let String allocate
|
||||
// memory in advance
|
||||
res.reserve((line_end - line_start) + 2 + (this->ctx - line_start) + 1 + 2);
|
||||
|
||||
// Write the line
|
||||
concat_hack(res, line_start, line_end - line_start);
|
||||
res += "\r\n";
|
||||
|
||||
// Write a marker to point out ctx
|
||||
while (line_start++ < this->ctx)
|
||||
res += ' ';
|
||||
res += '^';
|
||||
res += "\r\n";
|
||||
}
|
||||
res += this->err;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An OBIS id is 6 bytes, usually noted as a-b:c.d.e.f. Here we put them
|
||||
* in an array for easy parsing.
|
||||
*/
|
||||
struct ObisId {
|
||||
uint8_t v[6];
|
||||
|
||||
constexpr ObisId(uint8_t a, uint8_t b = 255, uint8_t c = 255, uint8_t d = 255, uint8_t e = 255, uint8_t f = 255)
|
||||
: v{a, b, c, d, e, f} { };
|
||||
constexpr ObisId() : v() {} // Zeroes
|
||||
|
||||
bool operator==(const ObisId &other) const {
|
||||
return memcmp(&v, &other.v, sizeof(v)) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dsmr
|
||||
|
||||
#endif // DSMR_INCLUDE_UTIL_H
|
||||
Reference in New Issue
Block a user