[WIP] New splitted up websocket API

This commit is contained in:
Martin Bauer 2021-06-06 10:49:09 +02:00
parent 5984a233af
commit 26d3469c83
5 changed files with 273 additions and 0 deletions

View File

@ -0,0 +1,24 @@
#pragma once
enum class MessageCode : uint8_t
{
// from swim tracker device to frontend
ERROR = 1,
INITIAL_INFO = 2,
SESSION_STARTED = 3,
SESSION_STOPPED = 4,
SESSION_NEW_DATA = 5,
ANSWER_USER_LIST = 6,
ANSWER_SESSION_LIST = 7,
// from frontend to device
START_SESSION = 128,
STOP_SESSION = 129,
TARE = 130,
QUERY_USER_LIST = 131,
QUERY_SESSION_LIST = 132,
WIFI_STATE_SET = 133,
WIFI_STATE_GET = 134,
};

169
firmware/src/SessionAPI.h Normal file
View File

@ -0,0 +1,169 @@
#include "Dtypes.h"
#include "MessageCodes.h"
#include "SwimTrackerConfig.h"
#include <ArduinoWebsockets.h>
#include <ArduinoJson.h>
template <typename T>
class SessionManager;
template <typename SessionT>
class SessionAPI
{
public:
SessionAPI(SessionManager<SessionT> &sessionManager)
: sessionManager_(sessionManager)
{
}
void onClientConnect(websockets::WebsocketsClient &client);
bool handleMessage(websockets::WebsocketsClient &client, MessageCode code, const char *payload, size_t size);
template <typename TServer>
void iteration(TServer &server);
private:
template <typename TServer>
void sendSessionStartMessages(TServer &server);
template <typename TServer>
void sendSessionStopMessages(TServer &server);
template <typename TServer>
void sendNewDataMessages(TServer &server);
SessionManager<SessionT> &sessionManager_;
size_t numSentMeasurements_[MAX_WEBSOCKET_CONNECTIONS];
bool running_;
};
// sending message about current session
template <typename T>
void SessionAPI<T>::onClientConnect(websockets::WebsocketsClient &client)
{
// TODO write msgpack instead for consistency?
using MeasurementT = typename T::MeasurementType;
// Message format:
// - uint8_t messageType
// - uint8_t running
// - uint32_t sessionId
// - MeasurementT [] measurements (if running)
auto &session = sessionManager_.session();
const auto numMeasurements = session.numMeasurements();
const auto sessionId = session.getStartTime();
const size_t msgSize = sizeof(uint8_t) + sizeof(uint8_t) + sizeof(sessionId) + sizeof(MeasurementT) * numMeasurements;
char *msg = (char *)heap_caps_malloc(msgSize, MALLOC_CAP_SPIRAM);
char *writeHead = msg;
*writeHead = MessageCode::INITIAL_INFO;
writeHead += sizeof(uint8_t);
*writeHead = sessionManager_.isMeasuring();
writeHead += sizeof(uint8_t);
*((uint32_t *)writeHead) = sessionManager_.isMeasuring() ? sessionId : 0;
writeHead += sizeof(uint32_t);
assert(writeHead - msg == msgSize - sizeof(MeasurementT) * numMeasurements);
memcpy(writeHead, session.getDataPointer(), sizeof(MeasurementT) * numMeasurements);
client.sendBinary(msg, msgSize);
free(msg);
}
template <typename T>
bool SessionAPI<T>::handleMessage(websockets::WebsocketsClient &client, MessageCode code,
const char *payload, size_t size)
{
switch (code)
{
case MessageCode::START_SESSION:
this->sessionManager_.startMeasurements();
return true;
case MessageCode::STOP_SESSION:
this->sessionManager_.stopMeasurements();
return true;
case MessageCode::TARE:
this->sessionManager_.tare();
return true;
}
return false;
}
template <typename T>
template <typename TServer>
void SessionAPI<T>::iteration(TServer &server)
{
if (!running_ && sessionManager_.isMeasuring())
{
sendSessionStartMessages(server);
for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i)
numSentMeasurements_[i] = 0;
}
else if (running_ && !sessionManager_.isMeasuring())
{
sendSessionStopMessages(server);
for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i)
numSentMeasurements_[i] = 0;
}
sendNewDataMessages(server);
}
template <typename T>
template <typename TServer>
void SessionAPI<T>::sendSessionStartMessages(TServer &server)
{
StaticJsonDocument<128> data;
data["sessionId"] = sessionManager_.session().getStartTime();
server.sendToAll<32>(MessageCode::SESSION_STARTED, data);
}
template <typename T>
template <typename TServer>
void SessionAPI<T>::sendSessionStopMessages(TServer &server)
{
MessageCode code = MessageCode::SESSION_STOPPED;
server.sendToAll<32>(code);
}
template <typename T>
template <typename TServer>
void SessionAPI<T>::sendNewDataMessages(TServer &server)
{
constexpr size_t MAX_MEASUREMENTS_PER_MSG = 16;
constexpr size_t WAIT_UNTIL_AT_LEAST_NUM_MEASUREMENTS = 1;
// new data messages are the only messages not sent in msgpack format
// since they are sent multiple times a second
using MeasurementT = typename T::MeasurementType;
auto &session = sessionManager_.session();
char buffer[1 + MAX_MEASUREMENTS_PER_MSG];
buffer[0] = MessageCode::SESSION_NEW_DATA;
constexpr int headerSize = 1;
for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i)
{
auto &c = server.client(i);
if (c.available())
{
MeasurementT *dataToSend = session.getDataPointer() + numSentMeasurements_[i];
int32_t numMeasurementsToSend = int32_t(session.numMeasurements()) - int32_t(numSentMeasurements_[i]);
if (numMeasurementsToSend >= WAIT_UNTIL_AT_LEAST_NUM_MEASUREMENTS)
{
if (numMeasurementsToSend > MAX_MEASUREMENTS_PER_MSG)
numMeasurementsToSend = MAX_MEASUREMENTS_PER_MSG;
memcpy(buffer + headerSize, dataToSend, sizeof(MeasurementT) * numMeasurementsToSend);
c.sendBinary(buffer, headerSize + sizeof(MeasurementT) * numMeasurementsToSend);
numSentMeasurements_[i] += numMeasurementsToSend;
}
}
}
}

46
firmware/src/WifiAPI.cpp Normal file
View File

@ -0,0 +1,46 @@
#include "WifiAPI.h"
#include "WifiManager.h"
#include "WebsocketServer.h"
bool WifiAPI::handleMessage(websockets::WebsocketsClient &client, MessageCode code, const char *payload, size_t size)
{
if (code == MessageCode::WIFI_STATE_GET)
{
StaticJsonDocument<128> data;
data["state"] = wifiManager_.stateStr();
sendToClient<64>(client, MessageCode::WIFI_STATE_GET, data);
return true;
}
else if (code == MessageCode::WIFI_STATE_SET)
{
StaticJsonDocument<1024> json;
DeserializationError err = deserializeJson(json, payload, size);
if (err)
{
sendErrorToClient(client, "Deserialization Error");
return true;
}
if (json.containsKey("reset_to_provisioning") && json["reset_to_provisioning"].as<bool>())
{
wifiManager_.resetToApProvisioning();
restartScheduled_ = true;
return true;
}
else if (json.containsKey("ap_password"))
{
wifiManager_.setApCredentials(json["ap_password"].as<const char *>());
restartScheduled_ = true;
return true;
}
else if (json.containsKey("sta_ssid") && json.containsKey("sta_password"))
{
wifiManager_.setStaCredentials(json["sta_ssid"].as<const char *>(), //
json["sta_password"].as<const char *>());
restartScheduled_ = true;
return true;
}
}
return false;
}

34
firmware/src/WifiAPI.h Normal file
View File

@ -0,0 +1,34 @@
#include "Dtypes.h"
#include "MessageCodes.h"
#include "SwimTrackerConfig.h"
#include <ArduinoWebsockets.h>
#include <ArduinoJson.h>
class WifiManager;
class WifiAPI
{
public:
WifiAPI(WifiManager &wifiManager)
: wifiManager_(wifiManager), restartScheduled_(false)
{
}
void onClientConnect(websockets::WebsocketsClient &client) {}
bool handleMessage(websockets::WebsocketsClient &client, MessageCode code, const char *payload, size_t size);
template <typename TServer>
void iteration(TServer &server)
{
if (restartScheduled_)
{
Serial.print("Restart triggered by WifiAPI");
ESP.restart();
}
}
private:
WifiManager &wifiManager_;
bool restartScheduled_;
};

Binary file not shown.