♻️ Updates combase to use protobufs
This commit is contained in:
@@ -1,15 +1,85 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <pb_encode.h>
|
#include <list>
|
||||||
#include <pb_decode.h>
|
#include <map>
|
||||||
#include <platform_shared/websocket_message.pb.h>
|
#include <type_traits>
|
||||||
|
#include <communication/proto_helpers.h>
|
||||||
|
|
||||||
enum message_type_t { CONNECT = 0, DISCONNECT = 1, EVENT = 2, PING = 3, PONG = 4, BINARY_EVENT = 5 };
|
template <typename T>
|
||||||
|
struct MessageTraits;
|
||||||
|
|
||||||
typedef std::function<void(JsonVariant &root, int originId)> EventCallback;
|
template <>
|
||||||
typedef std::function<void(const std::string &originId, bool sync)> SubscribeCallback;
|
struct MessageTraits<socket_message_IMUData> {
|
||||||
|
static constexpr pb_size_t tag = socket_message_WebsocketMessage_imu_tag;
|
||||||
|
static void assign(socket_message_WebsocketMessage& msg, const socket_message_IMUData& data) {
|
||||||
|
msg.message.imu = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct MessageTraits<socket_message_ModeData> {
|
||||||
|
static constexpr pb_size_t tag = socket_message_WebsocketMessage_mode_tag;
|
||||||
|
static void assign(socket_message_WebsocketMessage& msg, const socket_message_ModeData& data) {
|
||||||
|
msg.message.mode = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct MessageTraits<socket_message_AnalyticsData> {
|
||||||
|
static constexpr pb_size_t tag = socket_message_WebsocketMessage_analytics_tag;
|
||||||
|
static void assign(socket_message_WebsocketMessage& msg, const socket_message_AnalyticsData& data) {
|
||||||
|
msg.message.analytics = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct MessageTraits<socket_message_AnglesData> {
|
||||||
|
static constexpr pb_size_t tag = socket_message_WebsocketMessage_angles_tag;
|
||||||
|
static void assign(socket_message_WebsocketMessage& msg, const socket_message_AnglesData& data) {
|
||||||
|
msg.message.angles = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct MessageTraits<socket_message_RSSIData> {
|
||||||
|
static constexpr pb_size_t tag = socket_message_WebsocketMessage_rssi_tag;
|
||||||
|
static void assign(socket_message_WebsocketMessage& msg, const socket_message_RSSIData& data) {
|
||||||
|
msg.message.rssi = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct MessageTraits<socket_message_KinematicData> {
|
||||||
|
static constexpr pb_size_t tag = socket_message_WebsocketMessage_kinematic_data_tag;
|
||||||
|
static void assign(socket_message_WebsocketMessage& msg, const socket_message_KinematicData& data) {
|
||||||
|
msg.message.kinematic_data = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct MessageTraits<socket_message_IMUCalibrateData> {
|
||||||
|
static constexpr pb_size_t tag = socket_message_WebsocketMessage_imu_calibrate_tag;
|
||||||
|
static void assign(socket_message_WebsocketMessage& msg, const socket_message_IMUCalibrateData& data) {
|
||||||
|
msg.message.imu_calibrate = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct MessageTraits<socket_message_I2CScanData> {
|
||||||
|
static constexpr pb_size_t tag = socket_message_WebsocketMessage_i2c_scan_tag;
|
||||||
|
static void assign(socket_message_WebsocketMessage& msg, const socket_message_I2CScanData& data) {
|
||||||
|
msg.message.i2c_scan = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct MessageTraits<socket_message_PeripheralSettingsData> {
|
||||||
|
static constexpr pb_size_t tag = socket_message_WebsocketMessage_peripheral_settings_tag;
|
||||||
|
static void assign(socket_message_WebsocketMessage& msg, const socket_message_PeripheralSettingsData& data) {
|
||||||
|
msg.message.peripheral_settings = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class CommAdapterBase {
|
class CommAdapterBase {
|
||||||
public:
|
public:
|
||||||
@@ -18,142 +88,97 @@ class CommAdapterBase {
|
|||||||
|
|
||||||
virtual void begin() {}
|
virtual void begin() {}
|
||||||
|
|
||||||
bool hasSubscribers(const char *event) { return !client_subscriptions[event].empty(); }
|
bool hasSubscribers(int32_t tag) {
|
||||||
|
xSemaphoreTake(mutex_, portMAX_DELAY);
|
||||||
void onEvent(std::string event, EventCallback callback) { event_callbacks[event].push_back(std::move(callback)); }
|
bool result = !client_subscriptions_[tag].empty();
|
||||||
|
xSemaphoreGive(mutex_);
|
||||||
void onSubscribe(std::string event, SubscribeCallback callback) {
|
return result;
|
||||||
subscribe_callbacks[event].push_back(std::move(callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void emit(const char *event, JsonVariant &payload, const char *originId = "", bool onlyToSameOrigin = false) {
|
ProtoDecoder& decoder() { return decoder_; }
|
||||||
int originSubscriptionId = originId[0] ? atoi(originId) : -1;
|
|
||||||
xSemaphoreTake(mutex_, portMAX_DELAY);
|
template <typename T>
|
||||||
auto &subscriptions = client_subscriptions[event];
|
void emit(const T& data, int clientId = -1) {
|
||||||
if (subscriptions.empty()) {
|
constexpr pb_size_t tag = MessageTraits<T>::tag;
|
||||||
xSemaphoreGive(mutex_);
|
|
||||||
|
if (clientId < 0 && !hasSubscribers(tag)) return;
|
||||||
|
|
||||||
|
msg_.which_message = tag;
|
||||||
|
MessageTraits<T>::assign(msg_, data);
|
||||||
|
|
||||||
|
pb_ostream_t stream = pb_ostream_from_buffer(buffer_, sizeof(buffer_));
|
||||||
|
if (!pb_encode(&stream, socket_message_WebsocketMessage_fields, &msg_)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonDocument doc;
|
if (clientId >= 0) {
|
||||||
JsonArray array = doc.to<JsonArray>();
|
send(buffer_, stream.bytes_written, clientId);
|
||||||
array.add(static_cast<uint8_t>(message_type_t::EVENT));
|
} else {
|
||||||
array.add(event);
|
sendToSubscribers(tag, buffer_, stream.bytes_written);
|
||||||
array.add(payload);
|
}
|
||||||
|
|
||||||
#if USE_MSGPACK
|
|
||||||
std::string bin;
|
|
||||||
serializeMsgPack(doc, bin);
|
|
||||||
xSemaphoreGive(mutex_);
|
|
||||||
send(reinterpret_cast<const uint8_t *>(bin.data()), bin.size(), -1);
|
|
||||||
#else
|
|
||||||
String out;
|
|
||||||
serializeJson(doc, out);
|
|
||||||
xSemaphoreGive(mutex_);
|
|
||||||
send(out.c_str(), -1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void send_wsm_by_function( void (*setmsg)(socket_message_WebsocketMessage* message), int cid ) {
|
|
||||||
setmsg(&msg);
|
|
||||||
send_wsm(&msg, cid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
socket_message_WebsocketMessage msg;
|
virtual void send(const uint8_t* data, size_t len, int cid = -1) = 0;
|
||||||
uint8_t data_buffer[512];
|
|
||||||
void send(const char *data, int cid = -1) { send(reinterpret_cast<const uint8_t *>(data), strlen(data), cid); }
|
|
||||||
virtual void send(const uint8_t *data, size_t len, int cid = -1) = 0;
|
|
||||||
void send_wsm(socket_message_WebsocketMessage* message, int cid) {
|
|
||||||
pb_ostream_t ostream = pb_ostream_from_buffer(data_buffer, sizeof(data_buffer));
|
|
||||||
// Encode the message
|
|
||||||
bool ostatus = pb_encode(&ostream, &socket_message_WebsocketMessage_msg, message);
|
|
||||||
|
|
||||||
if (!ostatus) {
|
void subscribe(int32_t tag, int cid = 0) {
|
||||||
// TODO: Make a re-encoder using malloc instead (which increases exponentially but only if the error is the buffer size)
|
|
||||||
printf("Encoding of socket message failed: %s\n", PB_GET_ERROR(&ostream));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
send(data_buffer, ostream.bytes_written, cid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void subscribe(const char *event, int cid = 0) {
|
|
||||||
xSemaphoreTake(mutex_, portMAX_DELAY);
|
xSemaphoreTake(mutex_, portMAX_DELAY);
|
||||||
client_subscriptions[event].push_back(cid);
|
client_subscriptions_[tag].push_back(cid);
|
||||||
xSemaphoreGive(mutex_);
|
xSemaphoreGive(mutex_);
|
||||||
|
ESP_LOGI("ProtoComm", "Client %d subscribed to tag %d", cid, (int)tag);
|
||||||
}
|
}
|
||||||
void unsubscribe(const char *event, int cid = 0) {
|
|
||||||
|
void unsubscribe(int32_t tag, int cid = 0) {
|
||||||
xSemaphoreTake(mutex_, portMAX_DELAY);
|
xSemaphoreTake(mutex_, portMAX_DELAY);
|
||||||
client_subscriptions[event].remove(cid);
|
client_subscriptions_[tag].remove(cid);
|
||||||
|
xSemaphoreGive(mutex_);
|
||||||
|
ESP_LOGI("ProtoComm", "Client %d unsubscribed from tag %d", cid, (int)tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeClient(int cid) {
|
||||||
|
xSemaphoreTake(mutex_, portMAX_DELAY);
|
||||||
|
for (auto& [tag, clients] : client_subscriptions_) {
|
||||||
|
clients.remove(cid);
|
||||||
|
}
|
||||||
xSemaphoreGive(mutex_);
|
xSemaphoreGive(mutex_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleEventCallbacks(std::string event, JsonVariant &jsonObject, int originId) {
|
void handleIncoming(const uint8_t* data, size_t len, int cid) {
|
||||||
for (auto &callback : event_callbacks[event]) {
|
if (!decoder_.decode(data, len, cid)) {
|
||||||
callback(jsonObject, originId);
|
ESP_LOGE("ProtoComm", "Failed to decode incoming message from client %d", cid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void handleIncoming(const uint8_t *data, size_t len, int cid = 0) {
|
void sendPong(int cid) {
|
||||||
JsonDocument doc;
|
uint8_t pongBuffer[16];
|
||||||
#if USE_MSGPACK
|
msg_.which_message = socket_message_WebsocketMessage_pongmsg_tag;
|
||||||
DeserializationError error = deserializeMsgPack(doc, data, len);
|
msg_.message.pongmsg = socket_message_PongMsg_init_zero;
|
||||||
#else
|
pb_ostream_t stream = pb_ostream_from_buffer(pongBuffer, sizeof(pongBuffer));
|
||||||
DeserializationError error = deserializeJson(doc, data, len);
|
if (pb_encode(&stream, socket_message_WebsocketMessage_fields, &msg_)) {
|
||||||
#endif
|
send(pongBuffer, stream.bytes_written, cid);
|
||||||
if (error) {
|
|
||||||
ESP_LOGE("Comm Base", "Failed to deserialize incoming: (%s)", error.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonArray obj = doc.as<JsonArray>(); // TODO: Make const
|
|
||||||
message_type_t type = static_cast<message_type_t>(obj[0].as<uint8_t>());
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case message_type_t::CONNECT: {
|
|
||||||
const char *event = obj[1].as<const char *>();
|
|
||||||
ESP_LOGI("Comm Base", "CONNECT topic: %s (cid=%d)", event, cid);
|
|
||||||
subscribe(event, cid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case message_type_t::DISCONNECT: {
|
|
||||||
const char *event = obj[1].as<const char *>();
|
|
||||||
ESP_LOGI("Comm Base", "DISCONNECT topic: %s (cid=%d)", event, cid);
|
|
||||||
unsubscribe(event, cid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case message_type_t::EVENT: {
|
|
||||||
const char *event = obj[1].as<const char *>();
|
|
||||||
JsonVariant payload = obj[2].as<JsonVariant>();
|
|
||||||
handleEventCallbacks(event, payload, cid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case message_type_t::PING: {
|
|
||||||
ESP_LOGI("Comm Base", "PING (cid=%d)", cid);
|
|
||||||
ping(cid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case message_type_t::PONG: ESP_LOGI("Comm Base", "PONG (cid=%d)", cid); break;
|
|
||||||
default: ESP_LOGW("Comm Base", "Unknown message type: %d", static_cast<int>(type)); break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ping(int cid) {
|
void setupDecoderHandlers() {
|
||||||
#if USE_MSGPACK
|
decoder_.onSubscribe([this](int32_t tag, int cid) { subscribe(tag, cid); });
|
||||||
static const uint8_t pong[] = {0x91, 0x04};
|
|
||||||
send(pong, sizeof(pong), cid);
|
decoder_.onUnsubscribe([this](int32_t tag, int cid) { unsubscribe(tag, cid); });
|
||||||
#else
|
|
||||||
send("[4]", cid);
|
decoder_.onPing([this](int cid) { sendPong(cid); });
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SemaphoreHandle_t mutex_;
|
SemaphoreHandle_t mutex_;
|
||||||
std::map<std::string, std::list<int>> client_subscriptions;
|
std::map<int32_t, std::list<int>> client_subscriptions_;
|
||||||
std::map<std::string, std::list<EventCallback>> event_callbacks;
|
ProtoDecoder decoder_;
|
||||||
std::map<std::string, std::list<SubscribeCallback>> subscribe_callbacks;
|
socket_message_WebsocketMessage msg_ = socket_message_WebsocketMessage_init_zero;
|
||||||
};
|
uint8_t buffer_[PROTO_BUFFER_SIZE];
|
||||||
|
|
||||||
|
private:
|
||||||
|
void sendToSubscribers(int32_t tag, const uint8_t* data, size_t len) {
|
||||||
|
xSemaphoreTake(mutex_, portMAX_DELAY);
|
||||||
|
for (int cid : client_subscriptions_[tag]) {
|
||||||
|
send(data, len, cid);
|
||||||
|
}
|
||||||
|
xSemaphoreGive(mutex_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <pb_encode.h>
|
||||||
|
#include <pb_decode.h>
|
||||||
|
#include <platform_shared/websocket_message.pb.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#define PROTO_BUFFER_SIZE 512
|
||||||
|
|
||||||
|
class ProtoDecoder {
|
||||||
|
public:
|
||||||
|
using SubscribeHandler = std::function<void(int32_t tag, int clientId)>;
|
||||||
|
using UnsubscribeHandler = std::function<void(int32_t tag, int clientId)>;
|
||||||
|
using PingHandler = std::function<void(int clientId)>;
|
||||||
|
using ModeHandler = std::function<void(const socket_message_ModeData& data, int clientId)>;
|
||||||
|
using InputHandler = std::function<void(const socket_message_HumanInputData& data, int clientId)>;
|
||||||
|
using AnglesHandler = std::function<void(const socket_message_AnglesData& data, int clientId)>;
|
||||||
|
using KinematicHandler = std::function<void(const socket_message_KinematicData& data, int clientId)>;
|
||||||
|
using WalkGaitHandler = std::function<void(const socket_message_WalkGaitData& data, int clientId)>;
|
||||||
|
using IMUCalibrateExecHandler = std::function<void(int clientId)>;
|
||||||
|
using I2CScanRequestHandler = std::function<void(int clientId)>;
|
||||||
|
using PeripheralSettingsRequestHandler = std::function<void(int clientId)>;
|
||||||
|
|
||||||
|
void onSubscribe(SubscribeHandler handler) { subscribeHandler = handler; }
|
||||||
|
void onUnsubscribe(UnsubscribeHandler handler) { unsubscribeHandler = handler; }
|
||||||
|
void onPing(PingHandler handler) { pingHandler = handler; }
|
||||||
|
void onMode(ModeHandler handler) { modeHandler = handler; }
|
||||||
|
void onInput(InputHandler handler) { inputHandler = handler; }
|
||||||
|
void onAngles(AnglesHandler handler) { anglesHandler = handler; }
|
||||||
|
void onKinematic(KinematicHandler handler) { kinematicHandler = handler; }
|
||||||
|
void onWalkGait(WalkGaitHandler handler) { walkGaitHandler = handler; }
|
||||||
|
void onIMUCalibrateExec(IMUCalibrateExecHandler handler) { imuCalibrateExecHandler = handler; }
|
||||||
|
void onI2CScanRequest(I2CScanRequestHandler handler) { i2cScanRequestHandler = handler; }
|
||||||
|
void onPeripheralSettingsRequest(PeripheralSettingsRequestHandler handler) {
|
||||||
|
peripheralSettingsRequestHandler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool decode(const uint8_t* data, size_t len, int clientId) {
|
||||||
|
pb_istream_t stream = pb_istream_from_buffer(data, len);
|
||||||
|
|
||||||
|
if (!pb_decode(&stream, socket_message_WebsocketMessage_fields, &msg_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (msg_.which_message) {
|
||||||
|
case socket_message_WebsocketMessage_sub_notif_tag:
|
||||||
|
if (subscribeHandler) subscribeHandler(msg_.message.sub_notif.tag, clientId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case socket_message_WebsocketMessage_unsub_notif_tag:
|
||||||
|
if (unsubscribeHandler) unsubscribeHandler(msg_.message.unsub_notif.tag, clientId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case socket_message_WebsocketMessage_pingmsg_tag:
|
||||||
|
if (pingHandler) pingHandler(clientId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case socket_message_WebsocketMessage_mode_tag:
|
||||||
|
if (modeHandler) modeHandler(msg_.message.mode, clientId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case socket_message_WebsocketMessage_human_input_data_tag:
|
||||||
|
if (inputHandler) inputHandler(msg_.message.human_input_data, clientId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case socket_message_WebsocketMessage_angles_tag:
|
||||||
|
if (anglesHandler) anglesHandler(msg_.message.angles, clientId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case socket_message_WebsocketMessage_kinematic_data_tag:
|
||||||
|
if (kinematicHandler) kinematicHandler(msg_.message.kinematic_data, clientId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case socket_message_WebsocketMessage_walk_gait_tag:
|
||||||
|
if (walkGaitHandler) walkGaitHandler(msg_.message.walk_gait, clientId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case socket_message_WebsocketMessage_imu_calibrate_execute_tag:
|
||||||
|
if (imuCalibrateExecHandler) imuCalibrateExecHandler(clientId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case socket_message_WebsocketMessage_i2c_scan_data_request_tag:
|
||||||
|
if (i2cScanRequestHandler) i2cScanRequestHandler(clientId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case socket_message_WebsocketMessage_peripheral_settings_data_request_tag:
|
||||||
|
if (peripheralSettingsRequestHandler) peripheralSettingsRequestHandler(clientId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
socket_message_WebsocketMessage msg_ = socket_message_WebsocketMessage_init_zero;
|
||||||
|
SubscribeHandler subscribeHandler;
|
||||||
|
UnsubscribeHandler unsubscribeHandler;
|
||||||
|
PingHandler pingHandler;
|
||||||
|
ModeHandler modeHandler;
|
||||||
|
InputHandler inputHandler;
|
||||||
|
AnglesHandler anglesHandler;
|
||||||
|
KinematicHandler kinematicHandler;
|
||||||
|
WalkGaitHandler walkGaitHandler;
|
||||||
|
IMUCalibrateExecHandler imuCalibrateExecHandler;
|
||||||
|
I2CScanRequestHandler i2cScanRequestHandler;
|
||||||
|
PeripheralSettingsRequestHandler peripheralSettingsRequestHandler;
|
||||||
|
};
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef Socket_h
|
#pragma once
|
||||||
#define Socket_h
|
|
||||||
|
|
||||||
#include <PsychicHttp.h>
|
#include <PsychicHttp.h>
|
||||||
#include <template/stateful_service.h>
|
#include <template/stateful_service.h>
|
||||||
@@ -16,12 +15,6 @@ class Websocket : public CommAdapterBase {
|
|||||||
|
|
||||||
void begin() override;
|
void begin() override;
|
||||||
|
|
||||||
void onEvent(std::string event, EventCallback callback);
|
|
||||||
|
|
||||||
void emit(const char *event, JsonVariant &payload, const char *originId = "", bool onlyToSameOrigin = false);
|
|
||||||
|
|
||||||
void emit_raw(const char *event, uint8_t* payload, size_t event_length, size_t payload_length);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PsychicWebSocketHandler _socket;
|
PsychicWebSocketHandler _socket;
|
||||||
PsychicHttpServer &_server;
|
PsychicHttpServer &_server;
|
||||||
@@ -33,6 +26,3 @@ class Websocket : public CommAdapterBase {
|
|||||||
|
|
||||||
void send(const uint8_t *data, size_t len, int cid = -1) override;
|
void send(const uint8_t *data, size_t len, int cid = -1) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <features.h>
|
#include <features.h>
|
||||||
#include <settings/peripherals_settings.h>
|
#include <settings/peripherals_settings.h>
|
||||||
#include <template/stateful_endpoint.h>
|
#include <template/stateful_endpoint.h>
|
||||||
|
#include <platform_shared/websocket_message.pb.h>
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
@@ -47,11 +48,15 @@ class Peripherals : public StatefulService<PeripheralsConfiguration> {
|
|||||||
void scanI2C(uint8_t lower = 1, uint8_t higher = 127);
|
void scanI2C(uint8_t lower = 1, uint8_t higher = 127);
|
||||||
|
|
||||||
void getI2CResult(JsonVariant &root);
|
void getI2CResult(JsonVariant &root);
|
||||||
|
void getI2CResultProto(socket_message_I2CScanData &data);
|
||||||
|
|
||||||
void getIMUResult(JsonVariant &root);
|
void getIMUResult(JsonVariant &root);
|
||||||
|
void getIMUProto(socket_message_IMUData &data);
|
||||||
|
|
||||||
void getSonarResult(JsonVariant &root);
|
void getSonarResult(JsonVariant &root);
|
||||||
|
|
||||||
|
void getSettingsProto(socket_message_PeripheralSettingsData &data);
|
||||||
|
|
||||||
/* IMU FUNCTIONS */
|
/* IMU FUNCTIONS */
|
||||||
bool readImu();
|
bool readImu();
|
||||||
|
|
||||||
|
|||||||
+54
-37
@@ -111,7 +111,6 @@ void setupServer() {
|
|||||||
[&](PsychicRequest *request, JsonVariant &json) { return mdnsService.queryServices(request, json); });
|
[&](PsychicRequest *request, JsonVariant &json) { return mdnsService.queryServices(request, json); });
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Filesystem
|
// Filesystem
|
||||||
server.on("/api/config/*", HTTP_GET, [](PsychicRequest *request) { return FileSystem::getConfigFile(request); });
|
server.on("/api/config/*", HTTP_GET, [](PsychicRequest *request) { return FileSystem::getConfigFile(request); });
|
||||||
server.on("/api/files", HTTP_GET, [&](PsychicRequest *request) { return FileSystem::getFiles(request); });
|
server.on("/api/files", HTTP_GET, [&](PsychicRequest *request) { return FileSystem::getFiles(request); });
|
||||||
@@ -148,44 +147,45 @@ void setupServer() {
|
|||||||
|
|
||||||
void setupEventSocket() {
|
void setupEventSocket() {
|
||||||
// Motion events
|
// Motion events
|
||||||
socket.onEvent(INPUT_EVENT, [&](JsonVariant &root, int originId) { motionService.handleInput(root, originId); });
|
// socket.onEvent(INPUT_EVENT, [&](JsonVariant &root, int originId) { motionService.handleInput(root, originId); });
|
||||||
|
|
||||||
socket.onEvent(MODE_EVENT, [&](JsonVariant &root, int originId) {
|
// socket.onEvent(MODE_EVENT, [&](JsonVariant &root, int originId) {
|
||||||
servoController.setMode(SERVO_CONTROL_STATE::ANGLE);
|
// servoController.setMode(SERVO_CONTROL_STATE::ANGLE);
|
||||||
motionService.handleMode(root, originId);
|
// motionService.handleMode(root, originId);
|
||||||
motionService.isActive() ? servoController.activate() : servoController.deactivate();
|
// motionService.isActive() ? servoController.activate() : servoController.deactivate();
|
||||||
});
|
// });
|
||||||
|
|
||||||
socket.onEvent(WALK_GAIT_EVENT,
|
// socket.onEvent(WALK_GAIT_EVENT,
|
||||||
[&](JsonVariant &root, int originId) { motionService.handleWalkGait(root, originId); });
|
// [&](JsonVariant &root, int originId) { motionService.handleWalkGait(root, originId); });
|
||||||
|
|
||||||
socket.onEvent(ANGLES_EVENT, [&](JsonVariant &root, int originId) { motionService.anglesEvent(root, originId); });
|
// socket.onEvent(ANGLES_EVENT, [&](JsonVariant &root, int originId) { motionService.anglesEvent(root, originId);
|
||||||
|
// });
|
||||||
|
|
||||||
// Peripherals events
|
// // Peripherals events
|
||||||
socket.onEvent(EVENT_I2C_SCAN, [&](JsonVariant &root, int originId) {
|
// socket.onEvent(EVENT_I2C_SCAN, [&](JsonVariant &root, int originId) {
|
||||||
peripherals.scanI2C();
|
// peripherals.scanI2C();
|
||||||
JsonDocument doc;
|
// JsonDocument doc;
|
||||||
JsonVariant results = doc.to<JsonVariant>();
|
// JsonVariant results = doc.to<JsonVariant>();
|
||||||
peripherals.getI2CResult(results);
|
// peripherals.getI2CResult(results);
|
||||||
socket.emit(EVENT_I2C_SCAN, results);
|
// socket.emit(EVENT_I2C_SCAN, results);
|
||||||
});
|
// });
|
||||||
|
|
||||||
socket.onEvent(EVENT_IMU_CALIBRATE, [&](JsonVariant &root, int originId) {
|
// socket.onEvent(EVENT_IMU_CALIBRATE, [&](JsonVariant &root, int originId) {
|
||||||
JsonDocument doc;
|
// JsonDocument doc;
|
||||||
JsonVariant results = doc.to<JsonVariant>();
|
// JsonVariant results = doc.to<JsonVariant>();
|
||||||
results["success"] = peripherals.calibrateIMU();
|
// results["success"] = peripherals.calibrateIMU();
|
||||||
socket.emit(EVENT_IMU_CALIBRATE, results);
|
// socket.emit(EVENT_IMU_CALIBRATE, results);
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Servo controller events
|
// // Servo controller events
|
||||||
socket.onEvent(EVENT_SERVO_CONFIGURATION_SETTINGS,
|
// socket.onEvent(EVENT_SERVO_CONFIGURATION_SETTINGS,
|
||||||
[&](JsonVariant &root, int originId) { servoController.servoEvent(root, originId); });
|
// [&](JsonVariant &root, int originId) { servoController.servoEvent(root, originId); });
|
||||||
socket.onEvent(EVENT_SERVO_STATE,
|
// socket.onEvent(EVENT_SERVO_STATE,
|
||||||
[&](JsonVariant &root, int originId) { servoController.stateUpdate(root, originId); });
|
// [&](JsonVariant &root, int originId) { servoController.stateUpdate(root, originId); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR SpotControlLoopEntry(void *) {
|
void IRAM_ATTR SpotControlLoopEntry(void *) {
|
||||||
ESP_LOGI("main", "Setup complete now runing tsk");
|
ESP_LOGI("main", "Control task starting");
|
||||||
TickType_t xLastWakeTime = xTaskGetTickCount();
|
TickType_t xLastWakeTime = xTaskGetTickCount();
|
||||||
const TickType_t xFrequency = 5 / portTICK_PERIOD_MS;
|
const TickType_t xFrequency = 5 / portTICK_PERIOD_MS;
|
||||||
|
|
||||||
@@ -208,7 +208,7 @@ void IRAM_ATTR SpotControlLoopEntry(void *) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR serviceLoopEntry(void *) {
|
void IRAM_ATTR serviceLoopEntry(void *) {
|
||||||
ESP_LOGI("main", "Service control task starting");
|
ESP_LOGI("main", "Service task starting");
|
||||||
|
|
||||||
wifiService.begin();
|
wifiService.begin();
|
||||||
MDNS.begin(APP_NAME);
|
MDNS.begin(APP_NAME);
|
||||||
@@ -224,16 +224,33 @@ void IRAM_ATTR serviceLoopEntry(void *) {
|
|||||||
socket.begin();
|
socket.begin();
|
||||||
setupEventSocket();
|
setupEventSocket();
|
||||||
|
|
||||||
ESP_LOGI("main", "Service control task started");
|
ESP_LOGI("main", "Service task started");
|
||||||
for (;;) {
|
for (;;) {
|
||||||
wifiService.loop();
|
wifiService.loop();
|
||||||
apService.loop();
|
apService.loop();
|
||||||
EXECUTE_EVERY_N_MS(2000, system_service::emitMetrics(socket));
|
|
||||||
|
EXECUTE_EVERY_N_MS(2000, {
|
||||||
|
socket_message_AnalyticsData analytics = socket_message_AnalyticsData_init_zero;
|
||||||
|
analytics.max_alloc_heap = ESP.getMaxAllocHeap();
|
||||||
|
analytics.psram_size = ESP.getPsramSize();
|
||||||
|
analytics.free_psram = ESP.getFreePsram();
|
||||||
|
analytics.free_heap = ESP.getFreeHeap();
|
||||||
|
analytics.total_heap = ESP.getHeapSize();
|
||||||
|
analytics.min_free_heap = ESP.getMinFreeHeap();
|
||||||
|
analytics.core_temp = temperatureRead();
|
||||||
|
analytics.fs_total = ESP_FS.totalBytes();
|
||||||
|
analytics.fs_used = ESP_FS.usedBytes();
|
||||||
|
analytics.uptime = esp_timer_get_time() / 1000;
|
||||||
|
socket.emit(analytics);
|
||||||
|
});
|
||||||
|
|
||||||
EXECUTE_EVERY_N_MS(500, {
|
EXECUTE_EVERY_N_MS(500, {
|
||||||
JsonDocument doc;
|
socket_message_IMUData imu = socket_message_IMUData_init_zero;
|
||||||
JsonVariant results = doc.to<JsonVariant>();
|
peripherals.getIMUProto(imu);
|
||||||
peripherals.getIMUResult(results);
|
socket.emit(imu);
|
||||||
socket.emit(EVENT_IMU, results);
|
|
||||||
|
socket_message_RSSIData rssi = {.rssi = WiFi.RSSI()};
|
||||||
|
socket.emit(rssi);
|
||||||
});
|
});
|
||||||
|
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
|
|||||||
@@ -63,6 +63,15 @@ void Peripherals::getI2CResult(JsonVariant &root) {
|
|||||||
ESP_LOGI("Peripherals", "Emitting I2C scan results: %d", addressList.size());
|
ESP_LOGI("Peripherals", "Emitting I2C scan results: %d", addressList.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Peripherals::getI2CResultProto(socket_message_I2CScanData &data) {
|
||||||
|
data.devices_count = 0;
|
||||||
|
for (auto &address : addressList) {
|
||||||
|
if (data.devices_count >= 16) break;
|
||||||
|
data.devices[data.devices_count].address = address;
|
||||||
|
data.devices_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Peripherals::scanI2C(uint8_t lower, uint8_t higher) {
|
void Peripherals::scanI2C(uint8_t lower, uint8_t higher) {
|
||||||
addressList.clear();
|
addressList.clear();
|
||||||
for (uint8_t address = lower; address < higher; address++) {
|
for (uint8_t address = lower; address < higher; address++) {
|
||||||
@@ -76,6 +85,29 @@ void Peripherals::scanI2C(uint8_t lower, uint8_t higher) {
|
|||||||
ESP_LOGI("Peripherals", "Scan complete - Found %d device(s)", nDevices);
|
ESP_LOGI("Peripherals", "Scan complete - Found %d device(s)", nDevices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Peripherals::getIMUProto(socket_message_IMUData &data) {
|
||||||
|
#if FT_ENABLED(USE_MPU6050 || USE_BNO055)
|
||||||
|
data.x = _imu.getAngleX();
|
||||||
|
data.y = _imu.getAngleY();
|
||||||
|
data.z = _imu.getAngleZ();
|
||||||
|
#endif
|
||||||
|
#if FT_ENABLED(USE_HMC5883)
|
||||||
|
data.heading = _mag.getHeading();
|
||||||
|
#endif
|
||||||
|
#if FT_ENABLED(USE_BMP180)
|
||||||
|
data.altitude = _bmp.getAltitude();
|
||||||
|
data.bmp_temp = _bmp.getTemperature();
|
||||||
|
data.pressure = _bmp.getPressure();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peripherals::getSettingsProto(socket_message_PeripheralSettingsData &data) {
|
||||||
|
data.sda = state().sda;
|
||||||
|
data.scl = state().scl;
|
||||||
|
data.frequency = state().frequency;
|
||||||
|
data.pins_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* IMU FUNCTIONS */
|
/* IMU FUNCTIONS */
|
||||||
bool Peripherals::readImu() {
|
bool Peripherals::readImu() {
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user