Fixed scale tare
This commit is contained in:
parent
123c2a534b
commit
daa2454e71
|
@ -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__))
|
||||
|
|
|
@ -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
|
|
@ -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__))
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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() ) {
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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_;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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_;
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -1,11 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
//#define _HW_V_20
|
||||
|
||||
// HX711 load cell
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#ifdef _HW_V_20
|
||||
const int CONFIG_SCALE_DOUT_PIN = 23;
|
||||
const int CONFIG_SCALE_SCK_PIN = 22;
|
||||
#else
|
||||
const int CONFIG_SCALE_DOUT_PIN = 22;
|
||||
const int CONFIG_SCALE_SCK_PIN = 23;
|
||||
#endif
|
||||
|
||||
#else
|
||||
const int CONFIG_SCALE_DOUT_PIN = D2;
|
||||
const int CONFIG_SCALE_SCK_PIN = D3;
|
||||
const uint8_t CONFIG_TARE_AVG_COUNT = 50; // number of measurements in tare-phase (to find 0 )
|
||||
const int CONFIG_VALUE_DIVIDER = 128; // uint32 measurements are divided by this factor, before stored in uint16_t
|
||||
#endif
|
||||
const uint8_t CONFIG_MEASUREMENT_AVG_COUNT = 1; // number of measurements in normal phase
|
||||
const uint8_t CONFIG_TARE_AVG_COUNT = 6; // number of measurements in tare-phase (to find 0 )
|
||||
const int CONFIG_MEASURE_DELAY = 100; // interval in ms between measurements
|
||||
|
||||
//const int CONFIG_VALUE_DIVIDER = 8; // uint32 measurements are divided by this factor, before stored in uint16_t
|
||||
const int CONFIG_VALUE_DIVIDER = 256; // uint32 measurements are divided by this factor, before stored in uint16_t
|
||||
|
||||
const uint32_t CONFIG_SESSION_CHUNK_SIZE = 1024; //1024*8 - 16 * sizeof(uint32_t);
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
#ifdef USE_ESP32
|
||||
#include "SPIFFS.h"
|
||||
#else
|
||||
#include <FS.h>
|
||||
#endif
|
||||
|
||||
inline void printDeviceInfo()
|
||||
{
|
||||
/*
|
||||
FSInfo fs_info;
|
||||
SPIFFS.info(fs_info);
|
||||
|
||||
|
@ -66,4 +71,5 @@ inline void printDeviceInfo()
|
|||
str += "\r\n";
|
||||
}
|
||||
Serial.print(str);
|
||||
*/
|
||||
}
|
|
@ -1,7 +1,13 @@
|
|||
#define USE_ESP32
|
||||
|
||||
// Arduino & ESP headers
|
||||
#include <Arduino.h>
|
||||
#ifdef USE_ESP32
|
||||
#include <WiFi.h>
|
||||
#else
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#endif
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <WiFiUdp.h> // for NTP
|
||||
#include <NTPClient.h> // for NTP
|
||||
|
@ -9,6 +15,7 @@
|
|||
// Own libs
|
||||
#include "Dtypes.h"
|
||||
#include "MockScale.h"
|
||||
#include "Scale.h"
|
||||
#include "MeasurementSession.h"
|
||||
#include "SpiffsStorage.h"
|
||||
#include "DeviceInfoLog.h"
|
||||
|
@ -46,6 +53,7 @@ public:
|
|||
|
||||
void stopMeasurements() {
|
||||
measuring_ = false;
|
||||
session.finalize();
|
||||
}
|
||||
|
||||
bool isMeasuring() const {
|
||||
|
@ -54,12 +62,14 @@ public:
|
|||
|
||||
void iteration() {
|
||||
if( ! measuring_ ) {
|
||||
//Serial.println("Disabled");
|
||||
return;
|
||||
}
|
||||
uint16_t measurement;
|
||||
uint16_t measurement=-1;
|
||||
scale.measure(measurement);
|
||||
session.addPoint(measurement);
|
||||
|
||||
Serial.print("Measurement: ");
|
||||
Serial.println(measurement);
|
||||
if( lastCallTime_ != 0) {
|
||||
const long cycleDuration = millis() - lastCallTime_;
|
||||
if( cycleDuration <= CONFIG_MEASURE_DELAY)
|
||||
|
@ -69,8 +79,7 @@ public:
|
|||
else
|
||||
{
|
||||
const long skipped = (cycleDuration / CONFIG_MEASURE_DELAY);
|
||||
Serial.print("Warning: measurements skipped: ");
|
||||
Serial.println(skipped);
|
||||
//Serial.printf("Warning: measurements skipped: %d, cycleDuration %d", skipped, cycleDuration);
|
||||
|
||||
for(int i=0; i < skipped; ++i)
|
||||
session.addPoint(measurement);
|
||||
|
@ -84,7 +93,8 @@ public:
|
|||
Session_T & getSession() { return session; }
|
||||
|
||||
private:
|
||||
MockScale scale;
|
||||
Scale<CONFIG_VALUE_DIVIDER> scale;
|
||||
//MockScale scale;
|
||||
Session_T session;
|
||||
bool measuring_;
|
||||
long lastCallTime_;
|
||||
|
@ -100,12 +110,18 @@ template<typename Session_T>
|
|||
void httpSetup(SessionManager<Session_T> * sessionManager)
|
||||
{
|
||||
server.on("/api/session/start", HTTP_POST | HTTP_GET, [sessionManager](AsyncWebServerRequest * req) {
|
||||
req->send(200, "text/plain", F("OK"));
|
||||
AsyncWebServerResponse *response = req->beginResponse(200, "text/plain", F("OK"));
|
||||
response->addHeader("Access-Control-Allow-Origin", "*");
|
||||
req->send(response);
|
||||
//req->send(200, "text/plain", F("OK"));
|
||||
sessionManager->startMeasurements();
|
||||
Serial.println("Started measurements");
|
||||
});
|
||||
server.on("/api/session/stop", HTTP_POST | HTTP_GET, [sessionManager](AsyncWebServerRequest * req) {
|
||||
req->send(200, "text/plain", F("OK"));
|
||||
AsyncWebServerResponse *response = req->beginResponse(200, "text/plain", F("OK"));
|
||||
response->addHeader("Access-Control-Allow-Origin", "*");
|
||||
req->send(response);
|
||||
//req->send(200, "text/plain", F("OK"));
|
||||
sessionManager->stopMeasurements();
|
||||
Serial.println("Stopped measurements");
|
||||
});
|
||||
|
@ -114,6 +130,8 @@ void httpSetup(SessionManager<Session_T> * sessionManager)
|
|||
if( req->hasParam("startIdx") ) {
|
||||
startIdx = req->getParam("startIdx")->value().toInt();
|
||||
}
|
||||
Serial.print("Data request, start index: ");
|
||||
Serial.println(startIdx);
|
||||
|
||||
StreamingMsgPackEncoder<DummyWriter> encoderToDetermineSize(nullptr);
|
||||
encoderToDetermineSize.setSizeCountMode(true);
|
||||
|
@ -122,18 +140,14 @@ void httpSetup(SessionManager<Session_T> * sessionManager)
|
|||
Serial.print("Sending started of total size ");
|
||||
Serial.println(totalSize);
|
||||
auto callback = [=](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
|
||||
Serial.print("Partial send maxLen ");
|
||||
Serial.print(maxLen);
|
||||
Serial.print(" index ");
|
||||
Serial.println(index);
|
||||
CopyWriter copyWriter(buffer);
|
||||
ChunkedStreamingMsgPackEncoder<CopyWriter> encoder(©Writer, index, index + maxLen);
|
||||
sessionManager->getSession().serialize(encoder, startIdx);
|
||||
Serial.print("Bytes sent ");
|
||||
Serial.println(encoder.sentBytes() - index);
|
||||
return encoder.sentBytes() - index;
|
||||
};
|
||||
AsyncWebServerResponse *response = req->beginResponse("application/x-msgpack", totalSize, callback);
|
||||
response->addHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
auto sessionId = sessionManager->getSession().getStartTime();
|
||||
response->addHeader("content-disposition", "attachment; filename=\"" + String(sessionId) + ".st\"");
|
||||
req->send(response);
|
||||
|
@ -144,6 +158,38 @@ void httpSetup(SessionManager<Session_T> * sessionManager)
|
|||
server.begin();
|
||||
}
|
||||
|
||||
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
|
||||
Serial.printf("Listing directory: %s\r\n", dirname);
|
||||
|
||||
File root = fs.open(dirname);
|
||||
if(!root){
|
||||
Serial.println("- failed to open directory");
|
||||
return;
|
||||
}
|
||||
if(!root.isDirectory()){
|
||||
Serial.println(" - not a directory");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = root.openNextFile();
|
||||
while(file){
|
||||
if(file.isDirectory()){
|
||||
Serial.print(" DIR : ");
|
||||
Serial.println(file.name());
|
||||
if(levels){
|
||||
listDir(fs, file.name(), levels -1);
|
||||
}
|
||||
} else {
|
||||
Serial.print(" FILE: ");
|
||||
Serial.print(file.name());
|
||||
Serial.print("\tSIZE: ");
|
||||
Serial.println(file.size());
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Serial
|
||||
|
@ -153,14 +199,19 @@ void setup()
|
|||
Serial.println("----- New start -----");
|
||||
|
||||
// File system
|
||||
SPIFFS.begin();
|
||||
bool spiffsResult = SPIFFS.begin(true);
|
||||
Serial.printf("Spiffs begin %d\n", spiffsResult);
|
||||
|
||||
printDeviceInfo();
|
||||
|
||||
// WiFi
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD);
|
||||
WiFi.hostname(CONFIG_HOSTNAME);
|
||||
#ifdef USE_ESP32
|
||||
WiFi.setHostname(CONFIG_HOSTNAME);
|
||||
#else
|
||||
WIFI.hostname(CONFIG_HOSTNAME);
|
||||
#endif
|
||||
Serial.print(F("\n\n"));
|
||||
Serial.println(F("Waiting for WIFI connection..."));
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
|
@ -178,6 +229,9 @@ void setup()
|
|||
|
||||
// HTTP & Websocket server
|
||||
httpSetup(&sessionManager);
|
||||
|
||||
Serial.println("Spiffs listing:");
|
||||
listDir(SPIFFS, "/", 3);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
|
Loading…
Reference in New Issue