[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