aboutsummaryrefslogtreecommitdiff
path: root/confui
diff options
context:
space:
mode:
authorlonkaars <loek@pipeframe.xyz>2023-01-07 14:43:03 +0100
committerlonkaars <loek@pipeframe.xyz>2023-01-07 14:43:03 +0100
commitadb70d5ee1987cfb1680114d2db9786923aad1f1 (patch)
treea15de82808f40153cd285994cab7534ed9a10538 /confui
parent46ede2c109fe2aa390936ec4f0a30321fb7b5d86 (diff)
parentb083c8e08d610a4e74f39f66f3daa191301893b1 (diff)
Merge branch 'qt-gui-meshconnector-serial' into dev
Diffstat (limited to 'confui')
-rw-r--r--confui/confui.pro46
-rw-r--r--confui/main.cpp18
-rw-r--r--confui/main.h7
-rw-r--r--confui/mainwindow.cpp45
-rw-r--r--confui/mainwindow.h7
-rw-r--r--confui/makefile9
-rw-r--r--confui/mesh_connector.cpp112
-rw-r--r--confui/mesh_connector.h35
-rw-r--r--confui/serial.cpp198
-rw-r--r--confui/serial.h42
-rw-r--r--confui/ui_automation.cpp4
-rw-r--r--confui/ui_node.cpp7
12 files changed, 450 insertions, 80 deletions
diff --git a/confui/confui.pro b/confui/confui.pro
index 2c4df61..f73465b 100644
--- a/confui/confui.pro
+++ b/confui/confui.pro
@@ -1,24 +1,38 @@
-QT += core gui widgets
+QT += core gui widgets serialport
SOURCES += \
- main.cpp \
- mainwindow.cpp \
- mesh_connector.cpp \
- ui_tab_automations.cpp \
- ui_tab_node_overview.cpp \
- ui_node.cpp \
- ui_automation.cpp \
- ui_scroll_container.cpp
+ main.cpp \
+ mainwindow.cpp \
+ mesh_connector.cpp \
+ ui_tab_automations.cpp \
+ ui_tab_node_overview.cpp \
+ ui_node.cpp \
+ ui_automation.cpp \
+ ui_scroll_container.cpp \
+ serial.cpp \
+ ../shared/bin.c \
+ ../shared/protocol.c \
+ ../shared/serial_parse.c \
+ ../shared/pclient.c
HEADERS += \
- mainwindow.h \
- mesh_connector.h \
- ui_tab_automations.h \
- ui_tab_node_overview.h \
- ui_node.h \
- ui_automation.h \
- ui_scroll_container.h
+ mainwindow.h \
+ mesh_connector.h \
+ ui_tab_automations.h \
+ ui_tab_node_overview.h \
+ ui_node.h \
+ ui_automation.h \
+ ui_scroll_container.h \
+ serial.h \
+ ../shared/bin.h \
+ ../shared/protocol.h \
+ ../shared/serial_parse.h \
+ ../shared/consts.h \
+ main.h \
+ ../shared/pclient.h
CONFIG += c++17
CONFIG += force_debug_info
QMAKE_CXXFLAGS += -Wno-missing-field-initializers
+QMAKE_CFLAGS += -std=c11
+QMAKE_CFLAGS += -Wno-c99-designator
diff --git a/confui/main.cpp b/confui/main.cpp
index 6c3ab56..ae52a61 100644
--- a/confui/main.cpp
+++ b/confui/main.cpp
@@ -1,10 +1,18 @@
+#include "main.h"
#include "mainwindow.h"
-#include <QApplication>
+extern "C" {
+static const uint16_t _test = 1;
+static const uint8_t *_ptest = (uint8_t *)&_test;
+uint8_t g_cd_endianness;
+}
+
+CDMainWindow* g_cd_main_window = nullptr;
int main(int argc, char *argv[]) {
- QApplication a(argc, argv);
- CDMainWindow w;
- w.show();
- return a.exec();
+ g_cd_endianness = *_ptest;
+ g_cd_app = new QApplication(argc, argv);
+ g_cd_main_window = new CDMainWindow();
+ g_cd_main_window->show();
+ return g_cd_app->exec();
}
diff --git a/confui/main.h b/confui/main.h
new file mode 100644
index 0000000..10e9da6
--- /dev/null
+++ b/confui/main.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <QApplication>
+
+extern QApplication* g_cd_app;
+int main(int argc, char *argv[]);
+
diff --git a/confui/mainwindow.cpp b/confui/mainwindow.cpp
index cff5002..4c9b857 100644
--- a/confui/mainwindow.cpp
+++ b/confui/mainwindow.cpp
@@ -1,18 +1,29 @@
#include <QGridLayout>
#include <QMenuBar>
#include <QTabWidget>
+#include <iostream>
#include "mainwindow.h"
#include "ui_tab_automations.h"
#include "ui_tab_node_overview.h"
+#include "serial.h"
+#include "../shared/pclient.h"
+#include "main.h"
CDMeshConnector *g_cd_mesh_connector = nullptr;
+CDSerialConnector *g_cd_serial = nullptr;
+QApplication* g_cd_app = nullptr;
-CDMainWindow::~CDMainWindow() { delete this->mesh_connector; }
+CDMainWindow::~CDMainWindow() {
+ delete g_cd_mesh_connector;
+ delete g_cd_serial;
+}
CDMainWindow::CDMainWindow(QWidget *parent) : QMainWindow(parent) {
g_cd_mesh_connector = new CDMeshConnector();
this->mesh_connector = g_cd_mesh_connector;
+ g_cd_serial = new CDSerialConnector();
+ this->serial_connector = g_cd_serial;
menu_bar = new QMenuBar(this);
@@ -24,6 +35,10 @@ CDMainWindow::CDMainWindow(QWidget *parent) : QMainWindow(parent) {
tab_bar_widget->addTab(this->node_overview_tab, "node overview");
tab_bar_widget->addTab(this->automations_tab, "automations");
+ // manually connect to serial port
+ if (g_cd_app->arguments().length() > 1 && g_cd_app->arguments().at(1).length() > 0)
+ g_cd_serial->connect(g_cd_app->arguments().at(1).toStdString());
+
setMenuBar(menu_bar);
setCentralWidget(tab_bar_widget);
update();
@@ -45,10 +60,24 @@ void CDMainWindow::update() {
QAction *menu_options_add_automation = menu_options->addAction("add automation");
connect(menu_options_add_automation, &QAction::triggered, this, &CDMainWindow::menu_add_automation);
- QMenu *menu_options_serialport = menu_options->addMenu("serial port (FIXME)");
-
- menu_options_serialport->addAction("FIXME A");
- menu_options_serialport->addAction("FIXME B");
+ QString serial_port_menu_label = "serial port";
+ string port_name = g_cd_serial->get_port();
+ if (port_name.size() > 0) {
+ serial_port_menu_label.append(" (");
+ serial_port_menu_label.append(QString::fromStdString(port_name));
+ serial_port_menu_label.append(")");
+ }
+ QMenu *menu_options_serialport = menu_options->addMenu(serial_port_menu_label);
+
+ vector<string> ports = CDSerialConnector::get_ports();
+ for (string port : ports) {
+ QAction* menu_port = menu_options_serialport->addAction(QString::fromStdString(port));
+ connect(menu_port, &QAction::triggered, this, [this, port](){ menu_set_serial_port(port); });
+ }
+
+ cd_s_bin* msg = cd_cmd_gen_get_node(true, NULL);
+ cd_pclient_send(msg);
+ free(msg);
}
void CDMainWindow::menu_refresh() { update(); }
@@ -57,3 +86,9 @@ void CDMainWindow::menu_add_automation() {
g_cd_mesh_connector->create_link();
update();
}
+
+void CDMainWindow::menu_set_serial_port(string new_port) {
+ g_cd_serial->disconnect();
+ g_cd_serial->connect(new_port);
+ update();
+}
diff --git a/confui/mainwindow.h b/confui/mainwindow.h
index 3a0b4f7..4093cd1 100644
--- a/confui/mainwindow.h
+++ b/confui/mainwindow.h
@@ -6,9 +6,13 @@
#include <QDebug>
#include "mesh_connector.h"
+#include "serial.h"
class CDAutomationsTabWidget;
class CDNodeOverviewTabWidget;
+class CDMainWindow;
+
+extern CDMainWindow *g_cd_main_window;
/**
* @brief main window
@@ -26,6 +30,7 @@ private:
public:
CDMeshConnector *mesh_connector = nullptr;
+ CDSerialConnector *serial_connector = nullptr;
CDMainWindow(QWidget *parent = nullptr);
~CDMainWindow();
@@ -35,4 +40,6 @@ public:
virtual void menu_refresh();
/** @brief menu bar add automation action handler */
virtual void menu_add_automation();
+ /** @brief menu bar set serial port action handler */
+ void menu_set_serial_port(string new_port);
};
diff --git a/confui/makefile b/confui/makefile
index 930daed..2e22e20 100644
--- a/confui/makefile
+++ b/confui/makefile
@@ -7,12 +7,6 @@ endif
include confui.mk
-OBJECTS += $(patsubst %.c,%.o, $(wildcard ../shared/*.c))
-confui: $(OBJECTS)
-
-../shared/%.o: ../shared/%.c
- $(CC) -c $(CFLAGS) -w $< -o $@
-
FMT_FILES := $(DIST)
FMT_FILES := $(filter-out .%,$(FMT_FILES)) # filter hidden files
FMT_FILES := $(filter-out /%,$(FMT_FILES)) # filter files outside working directory
@@ -24,3 +18,6 @@ FMT_FILES := $(filter-out %.pro,$(FMT_FILES)) # filter *.pro
format:
clang-format -i $(FMT_FILES)
clang-tidy --fix-errors $(FMT_FILES)
+
+compile_commands:
+ compiledb make -Bn
diff --git a/confui/mesh_connector.cpp b/confui/mesh_connector.cpp
index 5b65d31..7ef0f02 100644
--- a/confui/mesh_connector.cpp
+++ b/confui/mesh_connector.cpp
@@ -4,6 +4,7 @@
#include <cstring>
#include <stdio.h>
+#include "../shared/pclient.h"
#include "mesh_connector.h"
using std::pair;
@@ -16,31 +17,32 @@ cd_link_t CDMeshConnector::get_new_link_id() { return _fresh_link_id++; }
cd_uid_t CDMeshConnector::get_new_node_id() { return _fresh_node_id++; }
CDMeshConnector::CDMeshConnector() {
- cd_uid_t berta = create_node({
- .address = {0x00, 0xff, 0x21, 0x69, 0xf2, 0x31},
- .name_len = 5,
- .name = "berta",
- .light_on = false,
- .provisioned = false,
- });
-
- cd_uid_t gerrit = create_node({
- .address = {0x0e, 0xf9, 0x46, 0x4d, 0xe8, 0x02},
- .name_len = 6,
- .name = "gerrit",
- .light_on = false,
- .provisioned = false,
- });
-
- create_link(berta, berta, CD_AUTOMATION_TYPE_TOGGLE);
- create_link(berta, berta, CD_AUTOMATION_TYPE_TOGGLE);
- create_link(gerrit, berta, CD_AUTOMATION_TYPE_TURN_OFF);
- create_link(gerrit, gerrit, CD_AUTOMATION_TYPE_TURN_ON);
+ // cd_uid_t berta = create_node({
+ // .address = {0x00, 0xff, 0x21, 0x69, 0xf2, 0x31},
+ // .name_len = 5,
+ // .name = "berta",
+ // .light_on = false,
+ // .provisioned = false,
+ // });
+
+ // cd_uid_t gerrit = create_node({
+ // .address = {0x0e, 0xf9, 0x46, 0x4d, 0xe8, 0x02},
+ // .name_len = 6,
+ // .name = "gerrit",
+ // .light_on = false,
+ // .provisioned = false,
+ // });
+
+ // create_link(berta, berta, CD_AUTOMATION_TYPE_TOGGLE);
+ // create_link(berta, berta, CD_AUTOMATION_TYPE_TOGGLE);
+ // create_link(gerrit, berta, CD_AUTOMATION_TYPE_TURN_OFF);
+ // create_link(gerrit, gerrit, CD_AUTOMATION_TYPE_TURN_ON);
return;
}
cd_uid_t CDMeshConnector::create_node(cd_s_node node) {
cd_s_node *_node = (cd_s_node *)malloc(sizeof(cd_s_node));
+ // TODO: handle empty structs
// id
cd_uid_t id = get_new_node_id();
@@ -98,7 +100,7 @@ map<cd_link_t, cd_s_automation *> CDMeshConnector::get_links(bool valid) {
return links;
}
-void CDMeshConnector::update_link(cd_s_automation *automation) {
+void CDMeshConnector::update_link(cd_s_automation *automation, bool publish) {
printf("link[%d]", automation->id);
if (automation->valid) {
printf(" = %.*s %s %.*s", (int)automation->button->name_len, automation->button->name,
@@ -110,9 +112,16 @@ void CDMeshConnector::update_link(cd_s_automation *automation) {
printf(" (invalid)");
}
printf("\n");
+
+ if (!publish) return;
+ if (!automation->valid) return;
+
+ cd_s_bin* msg = cd_cmd_gen_post_link_add(automation->button->uuid, automation->light->uuid, automation->type);
+ cd_pclient_send(msg);
+ free(msg);
}
-cd_link_t CDMeshConnector::create_link(cd_uid_t button, cd_uid_t light, enum cd_e_automation_type type) {
+cd_link_t CDMeshConnector::create_link(cd_uid_t button, cd_uid_t light, cd_e_automation_type type) {
cd_link_t id = get_new_link_id();
cd_s_automation *automation = (cd_s_automation *)malloc(sizeof(cd_s_automation));
@@ -146,11 +155,19 @@ cd_link_t CDMeshConnector::create_link() {
return id;
}
-void CDMeshConnector::remove_link(cd_link_t link_handle) {
+void CDMeshConnector::remove_link(cd_link_t link_handle, bool publish) {
printf("remove link[%d]\n", link_handle);
- if (_links[link_handle] != nullptr) free(_links[link_handle]);
+ if (_links.count(link_handle) == 0) return; // invalid handle
+ if (_links[link_handle] == nullptr) return; // already removed link
+
+ if (publish) {
+ cd_s_bin* msg = cd_cmd_gen_post_link_rm(_links[link_handle]->button->uuid, _links[link_handle]->light->uuid);
+ cd_pclient_send(msg);
+ free(msg);
+ }
+
+ free(_links[link_handle]);
_links[link_handle] = nullptr;
- return;
}
void CDMeshConnector::remove_node(cd_uid_t node_handle) {
@@ -160,21 +177,32 @@ void CDMeshConnector::remove_node(cd_uid_t node_handle) {
return;
}
-void CDMeshConnector::update_node(cd_s_node *node_ptr) {
+void CDMeshConnector::update_node(cd_s_node *node_ptr, bool publish) {
printf("turning %.*s %s\n", (int)node_ptr->name_len, node_ptr->name, node_ptr->light_on ? "on" : "off");
- return;
+
+ if (!publish) return;
+
+ cd_s_bin* msg = cd_cmd_gen_post_led(node_ptr->light_on, node_ptr->uuid);
+ cd_pclient_send(msg);
+ free(msg);
}
void CDMeshConnector::network_join_node(cd_s_node *node_ptr) {
- node_ptr->provisioned = true;
+ node_ptr->provisioned = true; //TODO: await success
printf("join %.*s into network\n", (int)node_ptr->name_len, node_ptr->name);
- return;
+
+ cd_s_bin* msg = cd_cmd_gen_post_net_add(node_ptr->uuid);
+ cd_pclient_send(msg);
+ free(msg);
}
void CDMeshConnector::network_remove_node(cd_s_node *node_ptr) {
- node_ptr->provisioned = false;
+ node_ptr->provisioned = false; //TODO: await success
printf("remove %.*s from network\n", (int)node_ptr->name_len, node_ptr->name);
- return;
+
+ cd_s_bin* msg = cd_cmd_gen_post_net_rm(node_ptr->uuid);
+ cd_pclient_send(msg);
+ free(msg);
}
string CDMeshConnector::cd_mac_to_string(cd_mac_addr_t mac) {
@@ -185,6 +213,28 @@ string CDMeshConnector::cd_mac_to_string(cd_mac_addr_t mac) {
return ret;
}
+string CDMeshConnector::cd_uuid_to_string(cd_uuid_t uuid) {
+ char *addr = nullptr;
+ asprintf(&addr, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
+ string ret = addr;
+ free(addr);
+ return ret;
+}
+
cd_s_automation *CDMeshConnector::get_link(cd_link_t id) { return _links[id]; }
cd_s_node *CDMeshConnector::get_node(cd_uid_t id) { return _nodes[id]; }
+
+cd_uid_t CDMeshConnector::get_or_create_node_by_uuid(cd_uuid_t uuid) {
+ for (pair<cd_uid_t, cd_s_node *> node : _nodes)
+ if (memcmp(node.second->uuid, uuid, sizeof(cd_uuid_t)) == 0) return node.first;
+ return create_node({});
+}
+
+cd_link_t CDMeshConnector::get_or_create_link_by_uuid(cd_uuid_t button, cd_uuid_t light) {
+ for (pair<cd_uid_t, cd_s_automation *> link : _links)
+ if (link.second != nullptr && link.second->valid == true &&
+ memcmp(link.second->button->uuid, button, sizeof(cd_uuid_t)) == 0 &&
+ memcmp(link.second->light->uuid, light, sizeof(cd_uuid_t)) == 0) return link.first;
+ return create_link();
+}
diff --git a/confui/mesh_connector.h b/confui/mesh_connector.h
index 176778f..8c1fc91 100644
--- a/confui/mesh_connector.h
+++ b/confui/mesh_connector.h
@@ -5,6 +5,8 @@
#include <string>
#include <vector>
+#include "../shared/protocol.h"
+
using std::array;
using std::map;
using std::size_t;
@@ -15,22 +17,19 @@ using std::vector;
typedef uint32_t cd_uid_t;
/** @brief link/automation id type */
typedef uint32_t cd_link_t;
-/** @brief node mac address type */
-typedef uint8_t cd_mac_addr_t[6];
-
-/** @brief automation types/actions */
-enum cd_e_automation_type {
- CD_AUTOMATION_TYPE_TOGGLE, /** @brief button toggles light */
- CD_AUTOMATION_TYPE_TURN_ON, /** @brief button always turns on light (regardless of previous state) */
- CD_AUTOMATION_TYPE_TURN_OFF, /** @brief button always turns off light (regardless of previous state) */
-};
+
+typedef cd_e_cmd_link_type cd_e_automation_type;
+#define CD_AUTOMATION_TYPE_TOGGLE CD_CMD_LINK_TYPE_TOGGLE
+#define CD_AUTOMATION_TYPE_TURN_ON CD_CMD_LINK_TYPE_TURN_ON
+#define CD_AUTOMATION_TYPE_TURN_OFF CD_CMD_LINK_TYPE_TURN_OFF
/** @brief GUI node representation */
typedef struct {
cd_uid_t id; /** @brief GUI-specific id (used as handle) */
cd_mac_addr_t address; /** @brief node bluetooth mac address */
+ cd_uuid_t uuid; /** @brief node uuid */
size_t name_len; /** @brief name length in bytes */
- const char *name; /** @brief user-friendly node name */
+ char *name; /** @brief user-friendly node name */
bool light_on; /** @brief state of light on node */
bool provisioned; /** @brief whether the node is provisioned into the network */
} cd_s_node;
@@ -102,6 +101,8 @@ public:
virtual cd_s_automation *get_link(cd_link_t id);
/** @brief get node pointer by node id */
virtual cd_s_node *get_node(cd_uid_t id);
+ virtual cd_uid_t get_or_create_node_by_uuid(cd_uuid_t uuid);
+ virtual cd_link_t get_or_create_link_by_uuid(cd_uuid_t button, cd_uuid_t light);
// network modification functions
/** @brief create empty automation */
@@ -114,7 +115,7 @@ public:
* @param light node id for node whose light will be used for this automation.
* @param action action/automation type (toggle, on, off).
*/
- virtual cd_link_t create_link(cd_uid_t button, cd_uid_t light, enum cd_e_automation_type action);
+ virtual cd_link_t create_link(cd_uid_t button, cd_uid_t light, cd_e_automation_type action);
/**
* @brief overwrite link id with new automation and update on network.
*
@@ -123,14 +124,16 @@ public:
* properties.
*
* @param automation pointer to automation struct (with new/modified values)
+ * @param publish `true` to send POST_LINK command
*/
- virtual void update_link(cd_s_automation *automation);
+ virtual void update_link(cd_s_automation *automation, bool publish = false);
/**
* @brief remove automation and update on network.
*
* @param link_handle automation id
+ * @param publish `true` to send POST_LINK command
*/
- virtual void remove_link(cd_link_t link_handle);
+ virtual void remove_link(cd_link_t link_handle, bool publish = false);
/**
* @brief overwrite node id with new node and update on network.
@@ -139,8 +142,9 @@ public:
* allocated using malloc()). used to update existing node properties.
*
* @param node_ptr pointer to node struct (with new/modified state)
+ * @param publish `true` to send POST_LED command
*/
- virtual void update_node(cd_s_node *node_ptr);
+ virtual void update_node(cd_s_node *node_ptr, bool publish = false);
/**
* @brief provision node into network
*
@@ -157,6 +161,9 @@ public:
// conversion functions
/** @brief convert `cd_mac_addr_t` to `std::string` for printing/GUI */
static string cd_mac_to_string(cd_mac_addr_t mac);
+ /** @brief convert `cd_uuid_t` to `std::string` for printing/GUI */
+ static string cd_uuid_to_string(cd_uuid_t uuid);
+
};
/** @brief global pointer to mesh connector, initialized in CDMainWindow */
diff --git a/confui/serial.cpp b/confui/serial.cpp
new file mode 100644
index 0000000..b3f1cd6
--- /dev/null
+++ b/confui/serial.cpp
@@ -0,0 +1,198 @@
+#include "serial.h"
+#include "../shared/serial_parse.h"
+#include "../shared/bin.h"
+#include "../shared/pclient.h"
+#include "mainwindow.h"
+#include "mesh_connector.h"
+
+#include <iostream>
+#include <QDebug>
+#include <QSerialPort>
+#include <QSerialPortInfo>
+
+CDSerialConnector::CDSerialConnector() {
+ this->_serial = new QSerialPort;
+
+ if (!_serial->setBaudRate(QSerialPort::Baud115200)) qDebug() << _serial->errorString();
+ if (!_serial->setDataBits(QSerialPort::Data8)) // data is 8 bits
+ qDebug() << _serial->errorString();
+ if (!_serial->setParity(QSerialPort::NoParity)) qDebug() << _serial->errorString();
+ if (!_serial->setFlowControl(QSerialPort::NoFlowControl)) // default: QSerialPort::NoFlowControl
+ qDebug() << _serial->errorString();
+ if (!_serial->setStopBits(QSerialPort::OneStop)) // default
+ qDebug() << _serial->errorString();
+}
+
+CDSerialConnector::~CDSerialConnector() { delete this->_serial; }
+
+void CDSerialConnector::action() {
+ int bytes = _serial->bytesAvailable();
+ if (bytes > 0) _msg = _serial->readAll();
+
+ string std_string = _msg.toStdString();
+ size_t size = std_string.size();
+ const char* data = std_string.c_str();
+ for (size_t i = 0; i < size; i++)
+ cd_serial_parse(data[i]);
+}
+
+void CDSerialConnector::write(QByteArray msg) {
+ if (-1 == _serial->write(msg))
+ qDebug() << _serial->errorString();
+}
+
+void CDSerialConnector::connect(string port) {
+ _serial->setPortName(QString::fromStdString(port));
+
+ if (!_serial->open(QIODevice::ReadWrite))
+ qDebug() << _serial->errorString();
+
+ QObject::connect(_serial, &QSerialPort::readyRead, [&] { action(); });
+}
+
+void CDSerialConnector::disconnect() {
+ if (_serial->isOpen() == false) return;
+ _serial->disconnect();
+}
+
+QByteArray CDSerialConnector::get_data() { return _msg; }
+
+vector<string> CDSerialConnector::get_ports() {
+ vector<string> ports;
+ for (QSerialPortInfo port : QSerialPortInfo::availablePorts())
+ ports.push_back(port.portName().toStdString());
+ return ports;
+}
+
+string CDSerialConnector::get_port() {
+ return _serial->portName().toStdString();
+}
+
+extern "C" {
+
+void cd_pclient_send(cd_s_bin* data) {
+ QByteArray converted;
+ converted.append("\xff", 1);
+ for (size_t i = 0; i < data->bytes; i++) {
+ size_t byte = data->data[i];
+ byte == 0xff ? converted.append("\xff\xff", 2)
+ : converted.append((char *) &byte, 1);
+ }
+ g_cd_serial->write(converted);
+}
+
+// receive handlers (node only)
+void cd_cmd_get_node(cd_s_bin* data) { (void) data; }
+void cd_cmd_post_led(cd_s_bin* data) { (void) data; }
+void cd_cmd_post_link(cd_s_bin* data) { (void) data; }
+void cd_cmd_post_net(cd_s_bin* data) { (void) data; }
+
+void cd_cmd_ping(cd_s_bin* data) {
+ CD_CAST_BIN(cd_s_cmd_ping, data, cast);
+
+ cd_bin_repl_ntoh16(&cast->id); // fix endianness
+
+ std::cout << "ping request with id " << cast->id << " received!" << std::endl;
+
+ cd_s_bin* response = cd_cmd_res_status((cd_e_scmds) cast->opcode, cast->id, false);
+ cd_pclient_send(response);
+ free(response);
+}
+
+void cd_cmd_response_get_node_parse_node(cd_s_cmd_node* node) {
+ printf("yes i am node with name '%.*s'\n", node->name_len, node->remaining_data);
+ printf("my light is %s and i am%s provisioned\n", node->light_on ? "on" : "off", node->provisioned ? "" : " not");
+
+ // get node handle
+ cd_uid_t node_id = g_cd_mesh_connector->get_or_create_node_by_uuid(node->uuid);
+ cd_s_node* gui_node = g_cd_mesh_connector->get_node(node_id);
+
+ // fill current node
+ memcpy(gui_node->address, node->address, sizeof(cd_mac_addr_t));
+ memcpy(gui_node->uuid, node->uuid, sizeof(cd_uuid_t));
+ gui_node->name_len = node->name_len;
+ if (gui_node->name != nullptr) free(gui_node->name);
+ char* name = (char*) malloc(node->name_len);
+ memcpy(name, node->remaining_data, node->name_len);
+ gui_node->name = name;
+ gui_node->light_on = !!node->light_on;
+ gui_node->provisioned = !!node->provisioned;
+
+ cd_uuid_t* light_publish_addresses = (cd_uuid_t*) (&node->remaining_data[0] + node->name_len);
+ for (unsigned i = 0; i < node->link_count; i++) {
+ // find or create light node
+ cd_uid_t light_id = g_cd_mesh_connector->get_or_create_node_by_uuid(light_publish_addresses[i]);
+ cd_s_node* gui_light = g_cd_mesh_connector->get_node(light_id);
+ memcpy(gui_light->uuid, light_publish_addresses[i], sizeof(cd_uuid_t)); // fill at least uuid (if node is not yet known)
+
+ // find or create automation handle
+ cd_link_t link_id = g_cd_mesh_connector->get_or_create_link_by_uuid(gui_light->uuid, light_publish_addresses[i]);
+ cd_s_automation* gui_link = g_cd_mesh_connector->get_link(link_id);
+
+ // fill automation
+ gui_link->button = gui_node;
+ gui_link->light = gui_light;
+ gui_link->type = CD_AUTOMATION_TYPE_TOGGLE; //TODO: read from incoming data in future
+ gui_link->valid = true;
+ }
+
+ g_cd_main_window->update();
+}
+
+void cd_cmd_response_get_node(cd_s_bin* data) {
+ CD_CAST_BIN(cd_s_cmd_response, data, response_cast);
+ cd_s_cmd_response_get_node* nodes = (cd_s_cmd_response_get_node*) &response_cast->response_info[0]; // yes
+ cd_bin_repl_ntoh16(&nodes->node_count);
+ cd_bin_repl_ntoh16(&nodes->remaining_size);
+
+ std::cout << "get nodes response with id " << response_cast->response_id << " received!" << std::endl;
+ printf("counting %d node%s\n", nodes->node_count, nodes->node_count == 1 ? "" : "s");
+
+ cd_s_cmd_node* cursor = &nodes->nodes[0];
+ for (unsigned int i = 0; i < nodes->node_count; i++) {
+ cd_bin_repl_ntoh16(&cursor->remaining_size);
+ cd_bin_repl_ntoh16(&cursor->link_count);
+ cd_bin_repl_ntoh32(&cursor->button_pub);
+
+ cd_cmd_response_get_node_parse_node(cursor);
+ cursor += sizeof(cd_s_cmd_node) + cd_bin_ntoh16(cursor->remaining_size);
+ }
+}
+
+void cd_cmd_response_ping(cd_s_bin* data) {
+ CD_CAST_BIN(cd_s_cmd_response, data, cast);
+ std::cout << "ping response with id " << cast->response_id << " received!" << std::endl;
+}
+
+void cd_cmd_response_post_led(cd_s_bin* data) {
+ CD_CAST_BIN(cd_s_cmd_response, data, cast);
+ if (cast->error) printf("POST_LED response with error for msg id 0x%04x", cast->response_id);
+}
+
+void cd_cmd_response_post_link(cd_s_bin* data) {
+ CD_CAST_BIN(cd_s_cmd_response, data, cast);
+ if (cast->error) printf("POST_LINK response with error for msg id 0x%04x", cast->response_id);
+}
+
+void cd_cmd_response_post_net(cd_s_bin* data) {
+ CD_CAST_BIN(cd_s_cmd_response, data, cast);
+ if (cast->error) printf("POST_NET response with error for msg id 0x%04x", cast->response_id);
+}
+
+void cd_cmd_response(cd_s_bin* data) {
+ CD_CAST_BIN(cd_s_cmd_response, data, cast);
+
+ cd_bin_repl_ntoh16(&cast->id);
+ cd_bin_repl_ntoh16(&cast->response_id);
+
+ switch (cast->response_type) {
+ case CD_CMD_PING: return cd_cmd_response_ping(data);
+ case CD_CMD_GET_NODE: return cd_cmd_response_get_node(data);
+ case CD_CMD_POST_LED: return cd_cmd_response_post_led(data);
+ case CD_CMD_POST_LINK: return cd_cmd_post_link(data);
+ case CD_CMD_POST_NET: return cd_cmd_response_post_net(data);
+ default: return;
+ }
+}
+
+}
diff --git a/confui/serial.h b/confui/serial.h
new file mode 100644
index 0000000..aa0508f
--- /dev/null
+++ b/confui/serial.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <QSerialPort>
+#include <QString>
+#include <vector>
+
+using std::string;
+using std::vector;
+
+/** @brief manage asynchronous serial connection */
+class CDSerialConnector {
+public:
+ CDSerialConnector();
+ virtual ~CDSerialConnector();
+
+ /** @brief get list of available serial ports */
+ static vector<string> get_ports();
+
+ /** @brief open serial port */
+ virtual void connect(string port);
+ /** @brief close serial port */
+ virtual void disconnect();
+
+ /** @brief write to serial port */
+ virtual void write(QByteArray msg);
+ /** @brief get last message */
+ virtual QByteArray get_data();
+
+ /** @brief get current port name */
+ virtual string get_port();
+
+private:
+ /** @brief executed when new data is received */
+ virtual void action();
+
+ QSerialPort *_serial = nullptr;
+ QByteArray _msg;
+};
+
+/** @brief global pointer to serial connector, initialized in CDMainWindow */
+extern CDSerialConnector *g_cd_serial;
+
diff --git a/confui/ui_automation.cpp b/confui/ui_automation.cpp
index eb6e1f6..2ade734 100644
--- a/confui/ui_automation.cpp
+++ b/confui/ui_automation.cpp
@@ -74,11 +74,11 @@ void CDAutomationWidget::apply() {
if (!conf_valid()) return;
_automation->button = g_cd_mesh_connector->get_node(dropdown_button->findData(dropdown_button->currentIndex()));
- _automation->type = (enum cd_e_automation_type)dropdown_action->findData(dropdown_action->currentIndex());
+ _automation->type = (cd_e_automation_type) dropdown_action->findData(dropdown_action->currentIndex());
_automation->light = g_cd_mesh_connector->get_node(dropdown_light->findData(dropdown_light->currentIndex()));
_automation->valid = true;
- g_cd_mesh_connector->update_link(_automation);
+ g_cd_mesh_connector->update_link(_automation, true);
}
void CDAutomationWidget::remove() {
diff --git a/confui/ui_node.cpp b/confui/ui_node.cpp
index 552b62a..09daaaa 100644
--- a/confui/ui_node.cpp
+++ b/confui/ui_node.cpp
@@ -1,4 +1,5 @@
#include "ui_node.h"
+#include "../shared/pclient.h"
CDNodeWidget::~CDNodeWidget() {}
CDNodeWidget::CDNodeWidget(QWidget *parent) : QWidget(parent) {
@@ -43,6 +44,10 @@ void CDNodeWidget::update() {
switch_on_off->setChecked(_node->light_on);
button_add_remove->setText(_node->provisioned ? "Remove from network" : "Join network");
+
+ cd_s_bin* msg = cd_cmd_gen_get_node(false, this->_node->uuid);
+ cd_pclient_send(msg);
+ free(msg);
}
void CDNodeWidget::toggle_provision() {
@@ -54,7 +59,7 @@ void CDNodeWidget::toggle_provision() {
void CDNodeWidget::update_led(bool on) {
_node->light_on = on;
- g_cd_mesh_connector->update_node(_node);
+ g_cd_mesh_connector->update_node(_node, true);
update();
}