[WIP] New splitted up websocket API
This commit is contained in:
parent
5984a233af
commit
26d3469c83
|
@ -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,
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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.
Loading…
Reference in New Issue