Fixed scale tare

This commit is contained in:
Martin Bauer
2020-06-05 20:55:01 +02:00
parent 123c2a534b
commit daa2454e71
14 changed files with 622 additions and 44 deletions

View File

@@ -17,4 +17,4 @@ inline String toString(const T & t) {
return String(t);
}
#define assert(EXPRESSION, MSG) ((EXPRESSION) ? (void)0 : _assert(#EXPRESSION, #MSG, __FILE__, __LINE__))
#define assert_msg(EXPRESSION, MSG) ((EXPRESSION) ? (void)0 : _assert(#EXPRESSION, #MSG, __FILE__, __LINE__))

View File

@@ -0,0 +1,181 @@
#pragma once
#ifdef PLATFORM_ESP32
#include "SPIFFS.h"
namespace portablefs
{
using File = ::File;
class Dir
{
public:
Dir() {}
Dir(const String &path)
: root_(SPIFFS.open(path))
{
//next();
}
bool next()
{
file_ = root_.openNextFile();
return file_;
}
bool isFile()
{
return !file_.isDirectory();
}
bool isDirectory()
{
return file_.isDirectory();
}
String fileName() const
{
return file_.name();
}
size_t fileSize() const
{
return file_.size();
}
private:
File root_;
File file_;
};
inline Dir openDir(const String &path)
{
return Dir(path);
}
inline File open(const char *name, const char *mode)
{
return SPIFFS.open(name, mode);
}
inline bool exists(const char *name)
{
return SPIFFS.exists(name);
}
inline bool remove(const char *name)
{
return SPIFFS.remove(name);
}
inline bool mkdir(const char *name)
{
return SPIFFS.mkdir(name);
}
} // namespace portablefs
#endif
#ifdef PLATFORM_ESP8266
#include <FS.h>
namespace portablefs
{
using Dir;
} // namespace portablefs
#endif
#ifdef PLATFORM_NATIVE
#include <string>
#include <fstream>
#include <filesystem>
#include "MockDtypes.h"
namespace fs = std::filesystem;
namespace portablefs
{
const std::string basePath = "./base";
class Dir
{
public:
Dir() {}
Dir(const String &path)
: it_(fs::directory_iterator(path).begin()),
end_(fs::directory_iterator(path).end()),
firstIncremented_(false)
{
}
bool next()
{
if (!firstIncremented_)
firstIncremented_ = true;
else
++it_;
return it_ != end_;
}
bool isFile()
{
return file.is_regular_file();
}
bool isDirectory()
{
return it_.is_directory();
}
String fileName() const
{
return it_.path().filename().string();
}
size_t fileSize() const
{
return it_.file_size();
}
private:
fs::directory_iterator it_;
fs::directory_iterator end_;
bool firstIncremented_;
};
inline Dir openDir(const String &path)
{
return Dir(path);
}
inline File open(const char *name, const char *mode)
{
if(mode == "r")
return fopen()
return SPIFFS.open(name, mode);
}
inline bool exists(const char *name)
{
return SPIFFS.exists(name);
}
inline bool remove(const char *name)
{
return SPIFFS.remove(name);
}
inline bool mkdir(const char *name)
{
return SPIFFS.mkdir(name);
}
} // namespace portablefs
#endif

View File

@@ -7,6 +7,7 @@
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
typedef uint32_t uint_t;
@@ -39,4 +40,7 @@ inline std::string toString(const T & t) {
return stream.str();
}
class String : public std::string
{};
#define assert(EXPRESSION, MSG) ((EXPRESSION) ? (void)0 : _assert(#EXPRESSION, #MSG, __FILE__, __LINE__))

View File

@@ -4,14 +4,16 @@
class MockScale
{
public:
MockScale( uint16_t valueMin=0, uint16_t valueMax=50)
MockScale( uint16_t valueMin=0, uint16_t valueMax=10)
: valueMin_(valueMin), valueMax_(valueMax), currentValue_(valueMin), direction(1)
{}
bool measure(uint16_t & measurementOut) {
currentValue_ += direction;
if ( currentValue_ >= valueMax_)
if ( currentValue_ >= valueMax_) {
direction = -1;
valueMax_ += 2;
}
else if ( currentValue_ <= valueMin_ )
direction = +1;

View File

@@ -1,4 +1,5 @@
#include "HX711.h"
#include "ConfigHardware.h"
#include <cstdint>
@@ -9,8 +10,11 @@ public:
bool measure(uint16_t & measurementOut) {
if (hx711_.is_ready())
{
uint32_t value = hx711_.get_value(MEASUREMENT_AVG_COUNT);
measurementOut = (int16_t)(value / DIVIDER);
long value = hx711_.read_average(CONFIG_MEASUREMENT_AVG_COUNT) - offset_;
if(value > 0)
measurementOut = (int16_t)(value / DIVIDER);
else
measurementOut = 0;
return true;
}
else
@@ -22,9 +26,10 @@ public:
};
void tare(uint32_t numMeasurementsToAverage=50) {
hx711_.tare(numMeasurementsToAverage);
offset_ = hx711_.read_average(numMeasurementsToAverage);
}
private:
HX711 hx711_;
long offset_ = 0;
};

View File

@@ -23,7 +23,7 @@ public:
Serial.println("Starting session rotate");
rotate();
const bool secondInsertSuccess = currentChunk->addPoint(measurement);
assert(secondInsertSuccess, "Session: insertion after rotation failed");
assert_msg(secondInsertSuccess, "Session: insertion after rotation failed");
// TODO check that there is place for file - remove old files
}
return true;
@@ -52,7 +52,7 @@ public:
encoder.template sendArrayHeader<Measurement_T>(lastIdx - startIdx);
while(startIdx < lastIdx)
startIdx = serializeChunk(encoder, startIdx);
assert(startIdx == lastIdx, "Not all data was sent");
assert_msg(startIdx == lastIdx, "Not all data was sent");
}
uint32_t getStartTime() const {
@@ -88,18 +88,18 @@ private:
template< typename Encoder_T>
uint32_t serializeChunk(Encoder_T & encoder, uint32_t startIdx) const {
assert( startIdx < currentChunk->getStartIndex() + currentChunk->numMeasurements(),
"serializeChunk: invalid startIdx" );
assert_msg( startIdx < currentChunk->getStartIndex() + currentChunk->numMeasurements(),
"serializeChunk: invalid startIdx" );
if( startIdx >= currentChunk->getStartIndex() ) {
const auto localStartIdx = startIdx - currentChunk->getStartIndex();
const auto numElements = currentChunk->numMeasurements() - localStartIdx;
assert(numElements <= currentChunk->numMeasurements(), "Internal problem in serializeChunk");
assert_msg(numElements <= currentChunk->numMeasurements(), "Internal problem in serializeChunk");
encoder.sendArrayPartialContents( currentChunk->getDataPointer() + localStartIdx, numElements );
return currentChunk->getStartIndex() + currentChunk->numMeasurements();
} else if( startIdx >= otherChunk->getStartIndex() && otherChunkFilled() ) {
encoder.sendArrayPartialContents( otherChunk->getDataPointer(), otherChunk->numMeasurements() );
assert( otherChunk->numMeasurements(), CHUNK_SIZE );
assert_msg( otherChunk->numMeasurements(), CHUNK_SIZE );
return otherChunk->getStartIndex() + otherChunk->numMeasurements();
} else {
if( encoder.getSizeCountMode() ) {

View File

@@ -1,7 +1,43 @@
#pragma once
#include "StreamingMsgPackEncoder.h"
#include <FS.h>
#include "FilesystemAbstraction.h"
#ifdef USE_ESP32
struct WriterAdaptor
{
File * f;
void write(const char * ptr, size_t size) {
f->write(reinterpret_cast<const uint8_t *>(ptr), size);
}
};
class SpiffsStorageWriter {
public:
SpiffsStorageWriter(const String &fileName) :
f_(SPIFFS.open(fileName, "w")),
adaptor_{&f_},
encoder_(&adaptor_),
fileName_(fileName)
{
bool success = f_;
Serial.println(success);
}
~SpiffsStorageWriter() {
f_.close();
Serial.println(fileName_);
Serial.println(SPIFFS.exists(fileName_));
}
StreamingMsgPackEncoder<WriterAdaptor> &encoder() { return encoder_; }
private:
File f_;
WriterAdaptor adaptor_;
StreamingMsgPackEncoder<WriterAdaptor> encoder_;
String fileName_;
};
#else
class SpiffsStorageWriter {
public:
@@ -26,6 +62,11 @@ private:
String fileName_;
};
#endif
class SpiffsStorageReader
{

View File

@@ -19,6 +19,7 @@ struct DummyWriter {
void write(const void*, uint32_t) {}
};
class CopyWriter {
public:
CopyWriter(uint8_t * bufferToWrite)
@@ -193,8 +194,8 @@ public:
uint32_t elementsToSkip = 0;
if( sentBytes_ < offsetToStart_ ) {
elementsToSkip = (offsetToStart_ - sentBytes_) / sizeof(T);
assert((offsetToStart_ - sentBytes_) % sizeof(T) == 0,
"Looks like previous sent operation send fraction of an element.");
assert_msg((offsetToStart_ - sentBytes_) % sizeof(T) == 0,
"Looks like previous sent operation send fraction of an element.");
}
if( elementsToSkip >= length) {
sentBytes_ += sizeof(T) * length;
@@ -241,7 +242,7 @@ private:
if( sentBytes_ < offsetToStart_ ) {
// already sent
sentBytes_ += sizeRequired;
assert( sentBytes_ <= offsetToStart_, "Partial sending not supported by this function" );
assert_msg( sentBytes_ <= offsetToStart_, "Partial sending not supported by this function" );
return;
}

192
lib/userdb/UserDB.cpp Normal file
View File

@@ -0,0 +1,192 @@
#include "UserDB.h"
#include "FilesystemAbstraction.h"
const String userDir = "/u/";
template <class ForwardIterator, class T>
ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T &val)
{
ForwardIterator it;
iterator_traits<ForwardIterator>::difference_type count, step;
count = distance(first, last);
while (count > 0)
{
it = first;
step = count / 2;
advance(it, step);
if (*it < val)
{
first = ++it;
count -= step + 1;
}
else
count = step;
}
return first;
}
static String userFileName(const String &userName)
{
return userDir + userName;
}
bool User::load(const String &name)
{
name_ = name;
assert(name_.length() > 0);
const auto fileName = userFileName(name_);
if (!portablefs::exists(fileName.c_str()))
return false;
auto file = portablefs::open(fileName.c_str(), "r");
size_t sessionsInFile;
file.read((uint8_t *)&sessionsInFile, sizeof(numSessions_));
init(name, sessionsInFile * 2);
size_t expectedSize = sizeof(SessionIdType) * numSessions_;
auto bytesRead = file.read((uint8_t *)sessionIds_, expectedSize);
numSessions_ = sessionsInFile;
assert(expectedSize == bytesRead);
}
void User::init(const String &name, size_t sessionAllocateSize)
{
if (sessionIds_ != nullptr)
{
free(sessionIds_);
sessionIds_ = nullptr;
}
name_ = name;
numSessionsAllocated_ = sessionAllocateSize;
sessionIds_ = (SessionIdType *)ps_malloc(sizeof(SessionIdType) * numSessionsAllocated_);
numSessions_ = 0;
}
void User::save()
{
if (!portablefs::exists(userDir.c_str()))
portablefs::mkdir(userDir.c_str());
auto file = portablefs::open(userFileName(name_).c_str(), "w");
file.write((uint8_t *)&numSessions_, sizeof(numSessions_));
file.write((uint8_t *)sessionIds_, sizeof(SessionIdType) * numSessions_);
}
void User::freeResources()
{
if (sessionIds_ != nullptr)
{
free(sessionIds_);
sessionIds_ = nullptr;
}
}
void User::remove()
{
portablefs::remove(userFileName(name_).c_str());
freeResources();
name_ = "";
numSessions_ = 0;
numSessionsAllocated_ = 0;
}
void User::growSessionArrayIfNecessary()
{
assert(numSessions_ <= numSessionsAllocated_);
if (numSessions_ < numSessionsAllocated_)
return;
numSessionsAllocated_ *= 2;
sessionIds_ = (SessionIdType *)ps_realloc(sessionIds_, numSessionsAllocated_);
assert(numSessions_ < numSessionsAllocated_);
}
void User::insertSession(SessionIdType newSessionId)
{
growSessionArrayIfNecessary();
assert(numSessionsAllocated_ > numSessions_);
SessionIdType *insertPos = lower_bound(sessionIds_, sessionIds_ + numSessions_, newSessionId);
const size_t moveStartIdx = sessionIds_ + numSessions_ - insertPos;
for (size_t i = numSessions_ - 1; i >= moveStartIdx; --i)
sessionIds_[i + 1] = sessionIds_[i];
sessionIds_[moveStartIdx] = newSessionId;
numSessions_ += 1;
}
bool User::removeSession(SessionIdType sessionIdToRemove)
{
SessionIdType *removePos = lower_bound(sessionIds_, sessionIds_ + numSessions_, sessionIdToRemove);
const size_t removeIdx = sessionIds_ + numSessions_ - removePos;
if (sessionIds_[removeIdx] != sessionIdToRemove)
return false;
for (size_t i = removeIdx; i < numSessions_ - 1; ++i)
sessionIds_[i] = sessionIds_[i + 1];
numSessions_ -= 1;
return true;
}
// --------------------------------------------------------------------------------------------------------------------
User *UserStorage::getUserInfo(const String &userName)
{
// index 0 is the unassigned user
for (size_t i = 1; i < numUsers_; ++i)
if (users_[i].name() == userName)
return &users_[i];
return nullptr;
}
User *UserStorage::getUnassignedUser()
{
return &users_[0];
}
User *UserStorage::addNewUser(const String &userName)
{
if (numUsers_ >= MAX_USERS)
return nullptr;
auto userIdx = numUsers_;
numUsers_++;
assert(numUsers_ < MAX_USERS);
users_[userIdx].init(userName);
}
bool UserStorage::deleteUser(const String &userName)
{
User *userPtr = getUserInfo(userName);
if (userPtr == nullptr)
return false;
size_t userIdx = userPtr - users_;
userPtr->remove();
assert(numUsers_ > 0);
if (userIdx != numUsers_ - 1)
users_[userIdx] = users_[numUsers_ - 1];
}
void UserStorage::fillFromFileSystem()
{
for (size_t i = 0; i < numUsers_; ++i)
users_[i].freeResources();
numUsers_ = 1;
users_[0].load("_unassigned");
portablefs::Dir d(userDir);
while (d.next())
{
if (d.isFile() && d.fileName()[0] != '_')
{
users_[numUsers_].load(d.fileName());
++numUsers_;
}
}
}

73
lib/userdb/UserDB.h Normal file
View File

@@ -0,0 +1,73 @@
#pragma once
#ifndef PLATFORM_NATIVE
#include <Arduino.h>
#endif
using SessionIdType = uint32_t;
constexpr size_t MAX_USERS = 64;
constexpr size_t INITIAL_SESSIONS_PER_USER = 128;
struct User
{
public:
User() : numSessions_(0), numSessionsAllocated_(0), sessionIds_(nullptr) {}
void init(const String &name, size_t sessionAllocateSize = INITIAL_SESSIONS_PER_USER);
void freeResources();
bool load(const String &name);
void save();
void remove();
bool valid() const { return sessionIds_ != nullptr; }
void insertSession(SessionIdType sessionId);
bool removeSession(SessionIdType sessionId);
bool hasSession(SessionIdType sessionId) const;
const String &name() const { return name_; }
// session access
SessionIdType *sessionBegin() { return sessionIds_; }
SessionIdType *sessionEnd() { return sessionIds_ + numSessions_; }
const SessionIdType *sessionBegin() const { return sessionIds_; }
const SessionIdType *sessionEnd() const { return sessionIds_ + numSessions_; }
private:
void growSessionArrayIfNecessary();
String name_;
size_t numSessions_;
size_t numSessionsAllocated_;
SessionIdType *sessionIds_;
};
class UserStorage
{
public:
UserStorage()
: numUsers_(0)
{
fillFromFileSystem();
}
User *getUserInfo(const String &userName);
User *getUnassignedUser();
User *addNewUser(const String &userName);
bool deleteUser(const String &userName);
User *begin() { return &users_[0]; }
User *end() { return &users_[numUsers_]; }
const User *begin() const { return &users_[0]; }
const User *end() const { return &users_[numUsers_]; }
private:
void fillFromFileSystem();
User users_[MAX_USERS];
size_t numUsers_;
};

View File

@@ -1,5 +1,6 @@
#include <ESPAsyncWebServer.h>
#include <FS.h>
#include "FilesystemAbstraction.h"
#define FLASH_TEXT(name) const char *name
@@ -35,7 +36,7 @@ public:
WebdavFileListCallback(const String &path)
: path_(path), headerWritten_(false), finished_(false)
{
dir_ = SPIFFS.openDir(path);
dir_ = portablefs::openDir(path);
}
size_t operator()(uint8_t *buffer, size_t maxLen, size_t index)
@@ -104,11 +105,11 @@ public:
}
size_t bytesWritten = buffer - bufferStart;
assert(bytesWritten < maxLen, "Written too much!");
Serial.print("Bytes written ");
Serial.println(bytesWritten);
Serial.print("Max bytes ");
Serial.println(maxLen);
assert_msg(bytesWritten < maxLen, "Written too much!");
//Serial.print("Bytes written ");
//Serial.println(bytesWritten);
//Serial.print("Max bytes ");
//Serial.println(maxLen);
return bytesWritten;
}
@@ -122,7 +123,7 @@ private:
{
size_t size = 0;
auto fileBase = fileZero.substring(0, fileZero.indexOf('_'));
auto newDirInstance = SPIFFS.openDir(path_);
auto newDirInstance = portablefs::openDir(path_);
while (newDirInstance.next())
if (newDirInstance.isFile() && newDirInstance.fileName().startsWith(fileBase))
size += newDirInstance.fileSize();
@@ -136,7 +137,7 @@ private:
buffer += len;
}
Dir dir_;
portablefs::Dir dir_;
const String path_;
bool headerWritten_;
bool finished_;
@@ -147,7 +148,7 @@ bool deleteMeasurementFiles(const String &stName, const String &folder)
String baseName = folder + "/" + stName.substring(0, stName.indexOf("."));
int counter = 0;
{
auto d = SPIFFS.openDir(folder);
auto d = portablefs::openDir(folder);
while (d.next())
if (d.isFile() && d.fileName().startsWith(baseName))
++counter;