From c265bc642b33c15f8446ceef318373a2f2bdee1d Mon Sep 17 00:00:00 2001 From: lonkaars Date: Sat, 10 Dec 2022 16:05:58 +0100 Subject: serial port list --- confui/confui.pro | 34 +++++++++++++++-------------- confui/mainwindow.cpp | 9 ++++++-- confui/mainwindow.h | 2 ++ confui/serial.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ confui/serial.h | 39 +++++++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+), 18 deletions(-) create mode 100644 confui/serial.cpp create mode 100644 confui/serial.h diff --git a/confui/confui.pro b/confui/confui.pro index 2c4df61..2992f70 100644 --- a/confui/confui.pro +++ b/confui/confui.pro @@ -1,23 +1,25 @@ -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 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 CONFIG += c++17 CONFIG += force_debug_info diff --git a/confui/mainwindow.cpp b/confui/mainwindow.cpp index cff5002..8dcf077 100644 --- a/confui/mainwindow.cpp +++ b/confui/mainwindow.cpp @@ -5,14 +5,18 @@ #include "mainwindow.h" #include "ui_tab_automations.h" #include "ui_tab_node_overview.h" +#include "serial.h" CDMeshConnector *g_cd_mesh_connector = nullptr; +CDSerialConnector *g_cd_serial = nullptr; CDMainWindow::~CDMainWindow() { delete this->mesh_connector; } 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); @@ -47,8 +51,9 @@ void CDMainWindow::update() { QMenu *menu_options_serialport = menu_options->addMenu("serial port (FIXME)"); - menu_options_serialport->addAction("FIXME A"); - menu_options_serialport->addAction("FIXME B"); + vector ports = CDSerialConnector::get_ports(); + for (string port : ports) + menu_options_serialport->addAction(QString::fromStdString(port)); } void CDMainWindow::menu_refresh() { update(); } diff --git a/confui/mainwindow.h b/confui/mainwindow.h index 3a0b4f7..41a0eac 100644 --- a/confui/mainwindow.h +++ b/confui/mainwindow.h @@ -6,6 +6,7 @@ #include #include "mesh_connector.h" +#include "serial.h" class CDAutomationsTabWidget; class CDNodeOverviewTabWidget; @@ -26,6 +27,7 @@ private: public: CDMeshConnector *mesh_connector = nullptr; + CDSerialConnector *serial_connector = nullptr; CDMainWindow(QWidget *parent = nullptr); ~CDMainWindow(); diff --git a/confui/serial.cpp b/confui/serial.cpp new file mode 100644 index 0000000..96c5c0f --- /dev/null +++ b/confui/serial.cpp @@ -0,0 +1,60 @@ +#include "serial.h" + +#include +#include +#include + +CDSerialConnector::CDSerialConnector() { + this->_serial = new QSerialPort; + + _serial->setPortName("/Users/jregnier/ttypx"); + if (!_serial->setBaudRate(QSerialPort::Baud9600)) 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() { + // this is called when readyRead(); + int bytes = _serial->bytesAvailable(); + if (bytes > 0) { + qDebug() << "new Data arived" << _serial->bytesAvailable(); + _msg = _serial->readAll(); + qDebug() << _msg; + } +} + +void CDSerialConnector::write(QByteArray msg) { + _serial->write(msg); + qDebug() << _serial->errorString(); +} + +void CDSerialConnector::connect() { + + // QIODevice::ReadOnly + if (!_serial->open(QIODevice::ReadWrite)) qDebug() << _serial->errorString(); + + QObject::connect(_serial, &QSerialPort::readyRead, [&] { + // this is called when readyRead(); + action(); + }); +} + +void CDSerialConnector::disconnect() { + // WIP? +} + +QByteArray CDSerialConnector::get_data() { return _msg; } + +vector CDSerialConnector::get_ports() { + vector ports; + for (QSerialPortInfo port : QSerialPortInfo::availablePorts()) + ports.push_back(port.portName().toStdString()); + return ports; +} diff --git a/confui/serial.h b/confui/serial.h new file mode 100644 index 0000000..9645227 --- /dev/null +++ b/confui/serial.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include + +using std::string; +using std::vector; + +/** @brief manage asynchronous serial connection */ +class CDSerialConnector { +public: + CDSerialConnector(); + ~CDSerialConnector(); + + /** @brief get list of available serial ports */ + static vector get_ports(); + + /** @brief open serial port */ + virtual void connect(); + /** @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(); + +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; + -- cgit v1.2.3 From ae3970ad5e1b3495726b70d5653c2424fccfba07 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Sun, 11 Dec 2022 16:13:03 +0100 Subject: add serial parser from robotrun to project --- confui/confui.pro | 11 +++- confui/makefile | 6 -- confui/mesh_connector.cpp | 8 +++ confui/mesh_connector.h | 6 +- shared/bin.c | 93 ++++++++++++++++++++++++++ shared/bin.h | 65 ++++++++++++++++++ shared/consts.h | 10 +++ shared/protocol.c | 30 +++++++++ shared/protocol.h | 163 ++++++++++++++++++++++++++++++++++++++++++++++ shared/protocol.md | 51 +++++++++++++++ shared/serial_parse.c | 61 +++++++++++++++++ shared/serial_parse.h | 17 +++++ 12 files changed, 511 insertions(+), 10 deletions(-) create mode 100644 shared/bin.c create mode 100644 shared/bin.h create mode 100644 shared/protocol.c create mode 100644 shared/protocol.h create mode 100644 shared/protocol.md create mode 100644 shared/serial_parse.c create mode 100644 shared/serial_parse.h diff --git a/confui/confui.pro b/confui/confui.pro index 2992f70..7dcd66c 100644 --- a/confui/confui.pro +++ b/confui/confui.pro @@ -9,7 +9,10 @@ SOURCES += \ ui_node.cpp \ ui_automation.cpp \ ui_scroll_container.cpp \ - serial.cpp + serial.cpp \ + ../shared/bin.c \ + ../shared/protocol.c \ + ../shared/serial_parse.c HEADERS += \ mainwindow.h \ @@ -19,7 +22,11 @@ HEADERS += \ ui_node.h \ ui_automation.h \ ui_scroll_container.h \ - serial.h + serial.h \ + ../shared/bin.h \ + ../shared/protocol.h \ + ../shared/serial_parse.h \ + ../shared/consts.h CONFIG += c++17 CONFIG += force_debug_info diff --git a/confui/makefile b/confui/makefile index 930daed..e1faed6 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 diff --git a/confui/mesh_connector.cpp b/confui/mesh_connector.cpp index 5b65d31..fd9c5fc 100644 --- a/confui/mesh_connector.cpp +++ b/confui/mesh_connector.cpp @@ -185,6 +185,14 @@ 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[15], uuid[14], uuid[13], uuid[12], uuid[11], uuid[10], uuid[9], uuid[8], uuid[7], uuid[6], uuid[5], uuid[4], uuid[3], uuid[2], uuid[1], uuid[0]); + 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]; } diff --git a/confui/mesh_connector.h b/confui/mesh_connector.h index 176778f..43f78d5 100644 --- a/confui/mesh_connector.h +++ b/confui/mesh_connector.h @@ -5,6 +5,8 @@ #include #include +#include "../shared/protocol.h" + using std::array; using std::map; using std::size_t; @@ -15,8 +17,6 @@ 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 { @@ -157,6 +157,8 @@ 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/shared/bin.c b/shared/bin.c new file mode 100644 index 0000000..fdceb30 --- /dev/null +++ b/shared/bin.c @@ -0,0 +1,93 @@ +#include +#include + +#include "bin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CD_ENDIAN_LITTLE (1) +#define CD_ENDIAN_BIG (0) + +#define _SHIFT_0B (8 * 0) +#define _SHIFT_1B (8 * 1) +#define _SHIFT_2B (8 * 2) +#define _SHIFT_3B (8 * 3) +#define _BYTE_0 ((uint32_t)0xff << (_SHIFT_0B)) +#define _BYTE_1 ((uint32_t)0xff << (_SHIFT_1B)) +#define _BYTE_2 ((uint32_t)0xff << (_SHIFT_2B)) +#define _BYTE_3 ((uint32_t)0xff << (_SHIFT_3B)) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshift-count-overflow" +cd_s_bin *cd_bin_from_uint8_t(uint8_t data) { + size_t size = 1; + cd_s_bin *ret = malloc(sizeof(cd_s_bin) + sizeof(uint8_t) * size); + ret->bytes = size; + ret->data[0] = data; + return ret; +} + +cd_s_bin *cd_bin_from_uint16_t(uint16_t data) { + size_t size = 2; + cd_s_bin *ret = malloc(sizeof(cd_s_bin) + sizeof(uint8_t) * size); + data = cd_bin_hton16(data); + ret->bytes = size; + ret->data[0] = (data & _BYTE_1) >> _SHIFT_1B; + ret->data[1] = (data & _BYTE_0) >> _SHIFT_0B; + return ret; +} + +cd_s_bin *cd_bin_from_uint32_t(uint32_t data) { + size_t size = 4; + cd_s_bin *ret = malloc(sizeof(cd_s_bin) + sizeof(uint8_t) * size); + data = cd_bin_hton32(data); + ret->bytes = size; + ret->data[0] = (data & _BYTE_3) >> _SHIFT_3B; + ret->data[1] = (data & _BYTE_2) >> _SHIFT_2B; + ret->data[2] = (data & _BYTE_1) >> _SHIFT_1B; + ret->data[3] = (data & _BYTE_0) >> _SHIFT_0B; + return ret; +} + +uint32_t cd_bin_hton32(uint32_t h32) { + if (g_cd_endianness == CD_ENDIAN_BIG) return h32; + return ((h32 & _BYTE_0) << _SHIFT_3B) | ((h32 & _BYTE_1) << _SHIFT_1B) | + ((h32 & _BYTE_2) >> _SHIFT_1B) | ((h32 & _BYTE_3) >> _SHIFT_3B); +} +#pragma GCC diagnostic pop + +uint16_t cd_bin_hton16(uint16_t h16) { + if (g_cd_endianness == CD_ENDIAN_BIG) return h16; + return ((h16 & _BYTE_0) << _SHIFT_1B) | ((h16 & _BYTE_1) >> _SHIFT_1B); +} + +uint32_t cd_bin_ntoh32(uint32_t n32) { return cd_bin_hton32(n32); } +uint16_t cd_bin_ntoh16(uint16_t n16) { return cd_bin_hton16(n16); } + +cd_s_bin *cd_bin_s_alloc(uint16_t bytes, uint8_t *data) { + cd_s_bin *temp = malloc(sizeof(cd_s_bin) + sizeof(uint8_t) * bytes); + temp->bytes = bytes; + memcpy(&temp->data, data, bytes); + return temp; +} + +cd_s_bin *cd_bin_s_cat(cd_s_bin *a, cd_s_bin *b) { + uint8_t data[a->bytes + b->bytes]; + memcpy(data, a->data, a->bytes); + memcpy(data + a->bytes, b->data, b->bytes); + cd_s_bin *c = cd_bin_s_alloc(a->bytes + b->bytes, data); + free(a); + free(b); + return c; +} + +void cd_bin_repl_hton32(uint32_t *h32) { *h32 = cd_bin_hton32(*h32); } +void cd_bin_repl_hton16(uint16_t *h16) { *h16 = cd_bin_hton16(*h16); } +void cd_bin_repl_ntoh32(uint32_t *h32) { *h32 = cd_bin_ntoh32(*h32); } +void cd_bin_repl_ntoh16(uint16_t *h16) { *h16 = cd_bin_ntoh16(*h16); } + +#ifdef __cplusplus +} +#endif diff --git a/shared/bin.h b/shared/bin.h new file mode 100644 index 0000000..35d2bc4 --- /dev/null +++ b/shared/bin.h @@ -0,0 +1,65 @@ +#pragma once + +/** @file bin.h */ + +/** + * helper file for binary data + * + * - fix endianness with functions inspired by UNIX arpa/inet.h + * - convert uint16_t and uint32_t to cd_s_bin + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint8_t g_cd_endianness; + +/** cast `in.data` to `type out` */ +#define CD_CAST_BIN(type, in, out) type *out = (type *)&in->data; +#define CD_CREATE_MSG_BIN(type, normal, bin) CD_CREATE_MSG_SIZE_BIN(type, sizeof(type), normal, bin) +/** @brief */ +#define CD_CREATE_MSG_SIZE_BIN(type, size, normal, bin) \ + cd_s_bin *bin = malloc(sizeof(cd_s_bin) + size); \ + bin->bytes = size; \ + type *normal = (type *)&bin->data; + +/** @brief hold binary data with fixed size */ +typedef struct { + uint16_t bytes; /** @brief data size */ + uint8_t data[]; /** @brief data */ +} cd_s_bin; + +/** @brief allocate new cd_s_bin struct and fill with `*data` for `bytes` bytes */ +cd_s_bin *cd_bin_s_alloc(uint16_t bytes, uint8_t *data); +/** @brief concatenate 2 cd_s_bin structs, deallocates `a` and `b` */ +cd_s_bin *cd_bin_s_cat(cd_s_bin *a, cd_s_bin *b); + +cd_s_bin *cd_bin_from_uint8_t(uint8_t data); +cd_s_bin *cd_bin_from_uint16_t(uint16_t data); +cd_s_bin *cd_bin_from_uint32_t(uint32_t data); + +/** @brief convert 32-bit value from host endian to network (big-endian) */ +uint32_t cd_bin_hton32(uint32_t h32); +/** @brief convert 16-bit value from host endian to network (big-endian) */ +uint16_t cd_bin_hton16(uint16_t h16); +/** @brief convert 32-bit value from network (big-endian) to host endian */ +uint32_t cd_bin_ntoh32(uint32_t n32); +/** @brief convert 16-bit value from network (big-endian) to host endian */ +uint16_t cd_bin_ntoh16(uint16_t n16); + +/** @brief replace 32-bit value from host endian to network (big-endian) */ +void cd_bin_repl_hton32(uint32_t *h32); +/** @brief replace 16-bit value from host endian to network (big-endian) */ +void cd_bin_repl_hton16(uint16_t *h16); +/** @brief replace 32-bit value from network (big-endian) to host endian */ +void cd_bin_repl_ntoh32(uint32_t *n32); +/** @brief replace 16-bit value from network (big-endian) to host endian */ +void cd_bin_repl_ntoh16(uint16_t *n16); + +#ifdef __cplusplus +} +#endif + diff --git a/shared/consts.h b/shared/consts.h index 6f70f09..57426bf 100644 --- a/shared/consts.h +++ b/shared/consts.h @@ -1 +1,11 @@ #pragma once + +/** @file consts.h */ + +/** @brief size of input (receive) buffer (in bytes) */ +#define CD_SERIAL_READ_BUFFER_SIZE 255 +/** @brief size of the error handling buffer (in errors, not bytes) */ +#define CD_ERROR_BUFFER_SIZE 16 +/** @brief size of the serial communication buffer (in messages, not bytes) */ +#define CD_SERCOMM_BUFFER_SIZE 16 + diff --git a/shared/protocol.c b/shared/protocol.c new file mode 100644 index 0000000..474398a --- /dev/null +++ b/shared/protocol.c @@ -0,0 +1,30 @@ +#include "protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +size_t cd_cmd_sizeof(uint8_t data[CD_SERIAL_READ_BUFFER_SIZE], uint8_t data_length) { + cd_cmd_opcode_t opcode = data[0]; + if (CD_CMD_HANDLERS_SIZE[opcode] > 0) return CD_CMD_HANDLERS_SIZE[opcode]; + + cd_s_bin *copy = cd_bin_s_alloc(data_length, data); + size_t length = (*CD_CMD_HANDLERS_SIZEOF[opcode])(copy); + + free(copy); + + return length; +} + +#define CD_DYN_MEMBER_SIZEOF(struct_t, length_byte, trailing_type) \ + sizeof(struct_t) + \ + (data->bytes > length_byte ? (sizeof(trailing_type) * data->data[length_byte]) : 0) + +size_t cd_cmd_response_sizeof(cd_s_bin* data) { + (void) data; // unused variable TODO: implement this + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/shared/protocol.h b/shared/protocol.h new file mode 100644 index 0000000..e2b3b1c --- /dev/null +++ b/shared/protocol.h @@ -0,0 +1,163 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** @file protocol.h */ + +#define CD_SERIAL_START_BYTE 0xff + +#include +#include + +#include "bin.h" +#include "consts.h" + +/** @brief mac address (00:11:22:33:44:55) */ +typedef uint8_t cd_mac_addr_t[6]; +/** @brief uuid (ffeeddcc-bbaa-9988-7766-554433221100) */ +typedef uint8_t cd_uuid_t[16]; + +/** @brief command opcode (identifies message type) */ +typedef uint8_t cd_cmd_opcode_t; +/** @brief command id (identifies messages uniquely) */ +typedef uint16_t cd_cmd_id_t; +/** @brief smallest boolean type */ +typedef uint8_t cd_cmd_bool_t; + +/** @brief cmd handler function signature */ +typedef void (cd_cmd_handler)(cd_s_bin *data); + +#pragma pack(push, 1) + +typedef struct { + cd_cmd_opcode_t opcode; /** @brief cmd opcode */ + cd_cmd_id_t id; /** @brief message id */ +} cd_s_cmd_ping; + +typedef struct { + cd_cmd_opcode_t opcode; /** @brief cmd opcode */ + cd_cmd_id_t id; /** @brief message id */ + cd_cmd_bool_t all; /** @brief get all known nodes */ + cd_uuid_t uuid; /** @brief node uuid to get details from, ignored if `all` = `true` */ +} cd_s_cmd_get_node; + +typedef struct { + cd_cmd_opcode_t opcode; /** @brief cmd opcode */ + cd_cmd_id_t id; /** @brief message id */ + cd_cmd_bool_t on; /** @brief new led status */ + cd_uuid_t uuid; /** @brief node uuid to set */ +} cd_s_cmd_post_led; + +typedef struct { + cd_cmd_opcode_t opcode; /** @brief cmd opcode */ + cd_cmd_id_t id; /** @brief message id */ +} cd_s_cmd_post_link; + +typedef struct { + cd_cmd_opcode_t opcode; /** @brief cmd opcode */ + cd_cmd_id_t id; /** @brief message id */ + cd_uuid_t uuid; /** @brief node uuid */ + cd_cmd_bool_t join; /** @brief `true` to join network, `false` to leave network */ +} cd_s_cmd_post_net; + +typedef struct { +} cd_s_cmd_response_ping; + +/** @brief protocol node */ +typedef struct { + cd_uuid_t uuid; /** @brief node network uuid */ + cd_mac_addr_t address; /** @brief node bluetooth mac address */ + uint8_t name_len; /** @brief name length in bytes */ + cd_cmd_bool_t light_on; /** @brief state of light on node */ + cd_cmd_bool_t provisioned; /** @brief whether the node is provisioned into the network */ + const char name[]; /** @brief user-friendly node name */ +} cd_s_cmd_node; + +typedef struct { + uint16_t node_count; + cd_s_cmd_node nodes[]; +} cd_s_cmd_response_get_node; + +typedef struct { +} cd_s_cmd_response_post_led; + +typedef struct { +} cd_s_cmd_response_post_link; + +typedef struct { +} cd_s_cmd_response_post_net; + +typedef struct { + cd_cmd_opcode_t opcode; /** @brief cmd opcode */ + cd_cmd_id_t id; /** @brief response message id */ + cd_cmd_bool_t success; /** @brief `true` if some error occurred */ + cd_cmd_id_t response_id; /** @brief original message id */ + cd_cmd_opcode_t response_type; /** @brief response type, used to cast type of `response_info` */ + uint16_t response_size; /** @brief size of remaining response */ + uint8_t response_info[]; /** @brief (CAST) remaining response struct, not read if `response_size`=`0` */ +} cd_s_cmd_response; + +#pragma pack(pop) + +/** @brief global handler for complete messages */ +void cd_cmd_handle(uint8_t data[CD_SERIAL_READ_BUFFER_SIZE], uint8_t length); +/** @brief calculate message length for any message */ +size_t cd_cmd_sizeof(uint8_t data[CD_SERIAL_READ_BUFFER_SIZE], uint8_t length); + +/** @brief calculate dynamic size of response message */ +size_t cd_cmd_response_sizeof(cd_s_bin* data); + +// down here is the garbage manual duplicate code section for constants + +#define CD_CMD_COUNT 6 +typedef enum { + CD_CMD_PING = 0x00, /** @brief send ping */ + CD_CMD_GET_NODE = 0x01, /** @brief get node(s) */ + CD_CMD_POST_LED = 0x02, /** @brief set led */ + CD_CMD_POST_LINK = 0x03, /** @brief set/remove link */ + CD_CMD_POST_NET = 0x04, /** @brief (un)register node with network */ + CD_CMD_RESPONSE = 0x05, /** @brief response message */ +} cd_e_scmds; + +cd_cmd_handler cd_cmd_ping, + cd_cmd_get_node, + cd_cmd_post_led, + cd_cmd_post_link, + cd_cmd_post_net, + cd_cmd_response; + +/** @brief constant message sizes, 0 for dynamic size */ +static const size_t CD_CMD_HANDLERS_SIZE[CD_CMD_COUNT] = { + [CD_CMD_PING] = sizeof(cd_s_cmd_ping), + [CD_CMD_GET_NODE] = sizeof(cd_s_cmd_get_node), + [CD_CMD_POST_LED] = sizeof(cd_s_cmd_post_led), + [CD_CMD_POST_LINK] = sizeof(cd_s_cmd_post_link), + [CD_CMD_POST_NET] = sizeof(cd_s_cmd_post_net), + [CD_CMD_RESPONSE] = 0, +}; + +/** @brief constant message sizes, 0 for dynamic size */ +static size_t (* const CD_CMD_HANDLERS_SIZEOF[CD_CMD_COUNT])(cd_s_bin*) = { + [CD_CMD_PING] = NULL, + [CD_CMD_GET_NODE] = NULL, + [CD_CMD_POST_LED] = NULL, + [CD_CMD_POST_LINK] = NULL, + [CD_CMD_POST_NET] = NULL, + [CD_CMD_RESPONSE] = &cd_cmd_response_sizeof, +}; + +/** @brief stores message handlers in array with opcode as index */ +static cd_cmd_handler* const CD_CMD_HANDLERS[CD_CMD_COUNT] = { + [CD_CMD_PING] = &cd_cmd_ping, + [CD_CMD_GET_NODE] = &cd_cmd_get_node, + [CD_CMD_POST_LED] = &cd_cmd_post_led, + [CD_CMD_POST_LINK] = &cd_cmd_post_link, + [CD_CMD_POST_NET] = &cd_cmd_post_net, + [CD_CMD_RESPONSE] = &cd_cmd_response, +}; + +#ifdef __cplusplus +} +#endif diff --git a/shared/protocol.md b/shared/protocol.md new file mode 100644 index 0000000..62caded --- /dev/null +++ b/shared/protocol.md @@ -0,0 +1,51 @@ +# protocol specs + +## commands + +each command consists of a start byte, opcode, and a payload. each opcode +defines logic to handle payload length, so certain commands might expect a +fixed-length payload, a variable-length payload, or none at all. the start byte +is `0xff`, and because most data sent is in binary format, if the data contains +an `0xff` byte, it will be escaped by replacing it with two `0xff` bytes. this +is converted to a single `0xff` on the receiving end, so these duplicated bytes +and the starting byte don't count towards message length. + +opcodes are picked sequentially, and are stored as enum constants inside +shared/protocol.h for code readability. + +|code|name|implemented|directions|full name| +|--:|---|:-:|:-:|---| +|`0x00`|[PING](#ping)|yes|`r <=> c`|ping +|`0x02`|[EXPT](#expt)|yes|`r --> c`|exception + +### PING + +#### ping (`r <=> c`) (2 bytes) + +|type|description| +|-:|-| +|`uint8_t`|opcode (`0x00 + 0` or `0x00 + 1`)| +|`uint8_t`|ping id| + +**ping** sends back an identical message either way with the **same** direction +bit. _ping id_ is a random 8-bit value that identifies the ping message. this +is the only command that makes either the robot or client send a message with +an opcode not matching the respective sender. the direction bit indicates which +device initiated the ping message. + +### EXPT + +#### exception (`r --> c`) (3+ bytes) + +|type|description| +|-:|-| +|`uint8_t`|opcode (`0x02 + 1`)| +|`uint8_t`|error code| +|`uint8_t`|length| +|`uint8_t[length]`|message contents| + +the **exception** instruction is used by the robot to send errors, warnings, +and other messages back to the client. an error can also optionally contain a +message between 0 and 255 characters long. message length is sent before the +message, and can be 0 in case of no message. + diff --git a/shared/serial_parse.c b/shared/serial_parse.c new file mode 100644 index 0000000..de48f60 --- /dev/null +++ b/shared/serial_parse.c @@ -0,0 +1,61 @@ +#include + +#include "consts.h" +#include "serial_parse.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool cd_serial_parse(uint8_t byte) { + static uint8_t current_message[CD_SERIAL_READ_BUFFER_SIZE] = {0}; + static uint8_t current_message_index = 0; + static uint8_t complete_message_length = 2; + + static bool attentive = false; + static bool listening = false; + + if (byte == CD_SERIAL_START_BYTE) { + attentive = !attentive; + if (attentive && listening) return CD_SERIAL_READ_SUCCESS; + } else if (attentive) { + attentive = false; + listening = !listening; + if (!listening) return CD_SERIAL_READ_FAILURE; + } + + if (!listening) return CD_SERIAL_READ_SUCCESS; + current_message[current_message_index++] = byte; + + complete_message_length = cd_cmd_sizeof(current_message, current_message_index); + + if (current_message_index == complete_message_length) { + cd_cmd_handle(current_message, current_message_index); + + memset(¤t_message, 0, CD_SERIAL_READ_BUFFER_SIZE); + current_message_index = 0; + complete_message_length = 1; + attentive = false; + listening = false; + return CD_SERIAL_READ_SUCCESS; + } + + return CD_SERIAL_READ_SUCCESS; +} + +void cd_cmd_handle(uint8_t data[CD_SERIAL_READ_BUFFER_SIZE], uint8_t data_length) { + cd_s_bin *copy = cd_bin_s_alloc(data_length, data); + + if (data[0] >= CD_CMD_COUNT) return; + cd_cmd_handler* handler = CD_CMD_HANDLERS[data[0]]; + + if (handler == NULL) return; + (*handler)(copy); + + free(copy); +} + +#ifdef __cplusplus +} +#endif + diff --git a/shared/serial_parse.h b/shared/serial_parse.h new file mode 100644 index 0000000..1efedc1 --- /dev/null +++ b/shared/serial_parse.h @@ -0,0 +1,17 @@ +#pragma once + +/** @file serial_parse.h */ + +#include +#include + +#include "protocol.h" + +#define CD_SERIAL_READ_SUCCESS true +#define CD_SERIAL_READ_FAILURE false + +/** + * parse serial data byte by byte + * @return true if read success, false if read fails + */ +bool cd_serial_parse(uint8_t byte); -- cgit v1.2.3 From 28cd1a0d195637f8f55faf711a66a3e0249843dc Mon Sep 17 00:00:00 2001 From: lonkaars Date: Sun, 11 Dec 2022 16:46:57 +0100 Subject: more serial worky --- confui/mainwindow.cpp | 21 ++++++++++++++++++--- confui/mainwindow.h | 2 ++ confui/serial.cpp | 31 ++++++++++++++++++++++++++++--- confui/serial.h | 5 ++++- shared/protocol.h | 16 ++++++++-------- shared/serial_parse.c | 2 +- 6 files changed, 61 insertions(+), 16 deletions(-) diff --git a/confui/mainwindow.cpp b/confui/mainwindow.cpp index 8dcf077..b0a1857 100644 --- a/confui/mainwindow.cpp +++ b/confui/mainwindow.cpp @@ -49,11 +49,20 @@ 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)"); + 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 ports = CDSerialConnector::get_ports(); - for (string port : ports) - menu_options_serialport->addAction(QString::fromStdString(port)); + 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); }); + } } void CDMainWindow::menu_refresh() { update(); } @@ -62,3 +71,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 41a0eac..587c447 100644 --- a/confui/mainwindow.h +++ b/confui/mainwindow.h @@ -37,4 +37,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/serial.cpp b/confui/serial.cpp index 96c5c0f..93adf28 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -1,5 +1,7 @@ #include "serial.h" +#include "../shared/serial_parse.h" +#include #include #include #include @@ -7,7 +9,6 @@ CDSerialConnector::CDSerialConnector() { this->_serial = new QSerialPort; - _serial->setPortName("/Users/jregnier/ttypx"); if (!_serial->setBaudRate(QSerialPort::Baud9600)) qDebug() << _serial->errorString(); if (!_serial->setDataBits(QSerialPort::Data8)) // data is 8 bits qDebug() << _serial->errorString(); @@ -28,6 +29,12 @@ void CDSerialConnector::action() { _msg = _serial->readAll(); qDebug() << _msg; } + + // 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) { @@ -35,7 +42,8 @@ void CDSerialConnector::write(QByteArray msg) { qDebug() << _serial->errorString(); } -void CDSerialConnector::connect() { +void CDSerialConnector::connect(string port) { + _serial->setPortName(QString::fromStdString(port)); // QIODevice::ReadOnly if (!_serial->open(QIODevice::ReadWrite)) qDebug() << _serial->errorString(); @@ -47,7 +55,8 @@ void CDSerialConnector::connect() { } void CDSerialConnector::disconnect() { - // WIP? + if (_serial->isOpen() == false) return; + _serial->disconnect(); } QByteArray CDSerialConnector::get_data() { return _msg; } @@ -58,3 +67,19 @@ vector CDSerialConnector::get_ports() { ports.push_back(port.portName().toStdString()); return ports; } + +string CDSerialConnector::get_port() { + return _serial->portName().toStdString(); +} + +extern "C" { + +void cd_cmd_response(cd_s_bin* data) { + (void) data; + + std::cout << "received!" << std::endl; + + return; +} + +} diff --git a/confui/serial.h b/confui/serial.h index 9645227..22f2542 100644 --- a/confui/serial.h +++ b/confui/serial.h @@ -17,7 +17,7 @@ public: static vector get_ports(); /** @brief open serial port */ - virtual void connect(); + virtual void connect(string port); /** @brief close serial port */ virtual void disconnect(); @@ -26,6 +26,9 @@ public: /** @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(); diff --git a/shared/protocol.h b/shared/protocol.h index e2b3b1c..c2001cf 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -27,7 +27,7 @@ typedef uint16_t cd_cmd_id_t; typedef uint8_t cd_cmd_bool_t; /** @brief cmd handler function signature */ -typedef void (cd_cmd_handler)(cd_s_bin *data); +typedef void (cd_cmd_handler_t)(cd_s_bin *data); #pragma pack(push, 1) @@ -121,12 +121,12 @@ typedef enum { CD_CMD_RESPONSE = 0x05, /** @brief response message */ } cd_e_scmds; -cd_cmd_handler cd_cmd_ping, - cd_cmd_get_node, - cd_cmd_post_led, - cd_cmd_post_link, - cd_cmd_post_net, - cd_cmd_response; +cd_cmd_handler_t cd_cmd_ping, + cd_cmd_get_node, + cd_cmd_post_led, + cd_cmd_post_link, + cd_cmd_post_net, + cd_cmd_response; /** @brief constant message sizes, 0 for dynamic size */ static const size_t CD_CMD_HANDLERS_SIZE[CD_CMD_COUNT] = { @@ -149,7 +149,7 @@ static size_t (* const CD_CMD_HANDLERS_SIZEOF[CD_CMD_COUNT])(cd_s_bin*) = { }; /** @brief stores message handlers in array with opcode as index */ -static cd_cmd_handler* const CD_CMD_HANDLERS[CD_CMD_COUNT] = { +static cd_cmd_handler_t* const CD_CMD_HANDLERS[CD_CMD_COUNT] = { [CD_CMD_PING] = &cd_cmd_ping, [CD_CMD_GET_NODE] = &cd_cmd_get_node, [CD_CMD_POST_LED] = &cd_cmd_post_led, diff --git a/shared/serial_parse.c b/shared/serial_parse.c index de48f60..bfc374a 100644 --- a/shared/serial_parse.c +++ b/shared/serial_parse.c @@ -47,7 +47,7 @@ void cd_cmd_handle(uint8_t data[CD_SERIAL_READ_BUFFER_SIZE], uint8_t data_length cd_s_bin *copy = cd_bin_s_alloc(data_length, data); if (data[0] >= CD_CMD_COUNT) return; - cd_cmd_handler* handler = CD_CMD_HANDLERS[data[0]]; + cd_cmd_handler_t* handler = CD_CMD_HANDLERS[data[0]]; if (handler == NULL) return; (*handler)(copy); -- cgit v1.2.3 From 52571310d06e2c20d2959c7f6ca2d9e6a1cf281c Mon Sep 17 00:00:00 2001 From: lonkaars Date: Mon, 12 Dec 2022 12:13:12 +0100 Subject: allow manual serial port specification --- confui/confui.pro | 3 ++- confui/main.cpp | 7 +++---- confui/main.h | 7 +++++++ confui/mainwindow.cpp | 7 +++++++ 4 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 confui/main.h diff --git a/confui/confui.pro b/confui/confui.pro index 7dcd66c..237f22d 100644 --- a/confui/confui.pro +++ b/confui/confui.pro @@ -26,7 +26,8 @@ HEADERS += \ ../shared/bin.h \ ../shared/protocol.h \ ../shared/serial_parse.h \ - ../shared/consts.h + ../shared/consts.h \ + main.h CONFIG += c++17 CONFIG += force_debug_info diff --git a/confui/main.cpp b/confui/main.cpp index 6c3ab56..52c54d8 100644 --- a/confui/main.cpp +++ b/confui/main.cpp @@ -1,10 +1,9 @@ +#include "main.h" #include "mainwindow.h" -#include - int main(int argc, char *argv[]) { - QApplication a(argc, argv); + g_cd_app = new QApplication(argc, argv); CDMainWindow w; w.show(); - return a.exec(); + 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 + +extern QApplication* g_cd_app; +int main(int argc, char *argv[]); + diff --git a/confui/mainwindow.cpp b/confui/mainwindow.cpp index b0a1857..1fd34c4 100644 --- a/confui/mainwindow.cpp +++ b/confui/mainwindow.cpp @@ -1,14 +1,17 @@ #include #include #include +#include #include "mainwindow.h" #include "ui_tab_automations.h" #include "ui_tab_node_overview.h" #include "serial.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; } @@ -28,6 +31,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(); -- cgit v1.2.3 From 8c21a929d06ed108b0e64f3892d036cd4cd67e51 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Mon, 12 Dec 2022 12:52:30 +0100 Subject: serial parser working on qt client side --- confui/confui.pro | 2 ++ confui/main.cpp | 7 +++++++ confui/serial.cpp | 36 ++++++++++++++++++++++++------------ shared/protocol-tests/ping.bin | Bin 0 -> 4 bytes shared/protocol.h | 12 ------------ shared/protocol.md | 36 ------------------------------------ shared/serial_parse.h | 9 +++++++++ 7 files changed, 42 insertions(+), 60 deletions(-) create mode 100644 shared/protocol-tests/ping.bin diff --git a/confui/confui.pro b/confui/confui.pro index 237f22d..023b31c 100644 --- a/confui/confui.pro +++ b/confui/confui.pro @@ -32,3 +32,5 @@ HEADERS += \ 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 52c54d8..a860f28 100644 --- a/confui/main.cpp +++ b/confui/main.cpp @@ -1,7 +1,14 @@ #include "main.h" #include "mainwindow.h" +extern "C" { +static const uint16_t _test = 1; +static const uint8_t *_ptest = (uint8_t *)&_test; +uint8_t g_cd_endianness; +} + int main(int argc, char *argv[]) { + g_cd_endianness = *_ptest; g_cd_app = new QApplication(argc, argv); CDMainWindow w; w.show(); diff --git a/confui/serial.cpp b/confui/serial.cpp index 93adf28..a20ae1c 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -1,5 +1,6 @@ #include "serial.h" #include "../shared/serial_parse.h" +#include "../shared/bin.h" #include #include @@ -22,19 +23,14 @@ CDSerialConnector::CDSerialConnector() { CDSerialConnector::~CDSerialConnector() { delete this->_serial; } void CDSerialConnector::action() { - // this is called when readyRead(); int bytes = _serial->bytesAvailable(); - if (bytes > 0) { - qDebug() << "new Data arived" << _serial->bytesAvailable(); - _msg = _serial->readAll(); - qDebug() << _msg; - } - - // 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]); + 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) { @@ -74,6 +70,22 @@ string CDSerialConnector::get_port() { extern "C" { +// 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 with id " << cast->id << " received!" << std::endl; + + // TODO: send ping back +} + void cd_cmd_response(cd_s_bin* data) { (void) data; diff --git a/shared/protocol-tests/ping.bin b/shared/protocol-tests/ping.bin new file mode 100644 index 0000000..2b8491c Binary files /dev/null and b/shared/protocol-tests/ping.bin differ diff --git a/shared/protocol.h b/shared/protocol.h index c2001cf..7f06a52 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -62,9 +62,6 @@ typedef struct { cd_cmd_bool_t join; /** @brief `true` to join network, `false` to leave network */ } cd_s_cmd_post_net; -typedef struct { -} cd_s_cmd_response_ping; - /** @brief protocol node */ typedef struct { cd_uuid_t uuid; /** @brief node network uuid */ @@ -80,15 +77,6 @@ typedef struct { cd_s_cmd_node nodes[]; } cd_s_cmd_response_get_node; -typedef struct { -} cd_s_cmd_response_post_led; - -typedef struct { -} cd_s_cmd_response_post_link; - -typedef struct { -} cd_s_cmd_response_post_net; - typedef struct { cd_cmd_opcode_t opcode; /** @brief cmd opcode */ cd_cmd_id_t id; /** @brief response message id */ diff --git a/shared/protocol.md b/shared/protocol.md index 62caded..c3c229f 100644 --- a/shared/protocol.md +++ b/shared/protocol.md @@ -13,39 +13,3 @@ and the starting byte don't count towards message length. opcodes are picked sequentially, and are stored as enum constants inside shared/protocol.h for code readability. -|code|name|implemented|directions|full name| -|--:|---|:-:|:-:|---| -|`0x00`|[PING](#ping)|yes|`r <=> c`|ping -|`0x02`|[EXPT](#expt)|yes|`r --> c`|exception - -### PING - -#### ping (`r <=> c`) (2 bytes) - -|type|description| -|-:|-| -|`uint8_t`|opcode (`0x00 + 0` or `0x00 + 1`)| -|`uint8_t`|ping id| - -**ping** sends back an identical message either way with the **same** direction -bit. _ping id_ is a random 8-bit value that identifies the ping message. this -is the only command that makes either the robot or client send a message with -an opcode not matching the respective sender. the direction bit indicates which -device initiated the ping message. - -### EXPT - -#### exception (`r --> c`) (3+ bytes) - -|type|description| -|-:|-| -|`uint8_t`|opcode (`0x02 + 1`)| -|`uint8_t`|error code| -|`uint8_t`|length| -|`uint8_t[length]`|message contents| - -the **exception** instruction is used by the robot to send errors, warnings, -and other messages back to the client. an error can also optionally contain a -message between 0 and 255 characters long. message length is sent before the -message, and can be 0 in case of no message. - diff --git a/shared/serial_parse.h b/shared/serial_parse.h index 1efedc1..1e9c404 100644 --- a/shared/serial_parse.h +++ b/shared/serial_parse.h @@ -10,8 +10,17 @@ #define CD_SERIAL_READ_SUCCESS true #define CD_SERIAL_READ_FAILURE false +#ifdef __cplusplus +extern "C" { +#endif + /** * parse serial data byte by byte * @return true if read success, false if read fails */ bool cd_serial_parse(uint8_t byte); + +#ifdef __cplusplus +} +#endif + -- cgit v1.2.3 From 61dd8a5ee66734dfd53ee9be725c9e71fd8d5414 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Mon, 12 Dec 2022 13:57:33 +0100 Subject: implement DYN_MEMBER_SIZEOF macro correctly and implement cd_cmd_response_sizeof --- confui/mainwindow.cpp | 5 ++++- confui/serial.h | 2 +- shared/bin.c | 8 ++++++++ shared/bin.h | 16 ++++++++++++++++ shared/protocol-tests/ping-response.bin | Bin 0 -> 10 bytes shared/protocol.c | 32 +++++++++++++++++++++++++++----- 6 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 shared/protocol-tests/ping-response.bin diff --git a/confui/mainwindow.cpp b/confui/mainwindow.cpp index 1fd34c4..b5bbdf0 100644 --- a/confui/mainwindow.cpp +++ b/confui/mainwindow.cpp @@ -13,7 +13,10 @@ 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(); diff --git a/confui/serial.h b/confui/serial.h index 22f2542..aa0508f 100644 --- a/confui/serial.h +++ b/confui/serial.h @@ -11,7 +11,7 @@ using std::vector; class CDSerialConnector { public: CDSerialConnector(); - ~CDSerialConnector(); + virtual ~CDSerialConnector(); /** @brief get list of available serial ports */ static vector get_ports(); diff --git a/shared/bin.c b/shared/bin.c index fdceb30..875d013 100644 --- a/shared/bin.c +++ b/shared/bin.c @@ -65,6 +65,14 @@ uint16_t cd_bin_hton16(uint16_t h16) { uint32_t cd_bin_ntoh32(uint32_t n32) { return cd_bin_hton32(n32); } uint16_t cd_bin_ntoh16(uint16_t n16) { return cd_bin_hton16(n16); } +uint32_t cd_bin_ntohd(uint8_t* n, size_t s) { return cd_bin_htond(n, s); } + +uint32_t cd_bin_htond(uint8_t* h, size_t s) { + if (s == sizeof(uint8_t)) return *h; + else if (s == sizeof(uint16_t)) return cd_bin_hton16(*(uint16_t*) h); + else if (s == sizeof(uint32_t)) return cd_bin_hton32(*(uint32_t*) h); + else return 0; +} cd_s_bin *cd_bin_s_alloc(uint16_t bytes, uint8_t *data) { cd_s_bin *temp = malloc(sizeof(cd_s_bin) + sizeof(uint8_t) * bytes); diff --git a/shared/bin.h b/shared/bin.h index 35d2bc4..0e16ec0 100644 --- a/shared/bin.h +++ b/shared/bin.h @@ -10,6 +10,7 @@ */ #include +#include #ifdef __cplusplus extern "C" { @@ -50,6 +51,21 @@ uint32_t cd_bin_ntoh32(uint32_t n32); /** @brief convert 16-bit value from network (big-endian) to host endian */ uint16_t cd_bin_ntoh16(uint16_t n16); +/** + * @brief convert (8*s)-bit value from network (big-endian) to host endian + * (dynamic size) + * + * @param n pointer to number + * @param s size of number in bytes + * + * @return 32-bit integer regardless of `s` + * + * this function is exclusively used by the CD_DYN_MEMBER_SIZEOF macro in + * shared/protocol.c + */ +uint32_t cd_bin_ntohd(uint8_t* n, size_t s); +uint32_t cd_bin_htond(uint8_t* h, size_t s); + /** @brief replace 32-bit value from host endian to network (big-endian) */ void cd_bin_repl_hton32(uint32_t *h32); /** @brief replace 16-bit value from host endian to network (big-endian) */ diff --git a/shared/protocol-tests/ping-response.bin b/shared/protocol-tests/ping-response.bin new file mode 100644 index 0000000..6067349 Binary files /dev/null and b/shared/protocol-tests/ping-response.bin differ diff --git a/shared/protocol.c b/shared/protocol.c index 474398a..1d66f17 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -1,3 +1,5 @@ +#include + #include "protocol.h" #ifdef __cplusplus @@ -16,13 +18,33 @@ size_t cd_cmd_sizeof(uint8_t data[CD_SERIAL_READ_BUFFER_SIZE], uint8_t data_leng return length; } -#define CD_DYN_MEMBER_SIZEOF(struct_t, length_byte, trailing_type) \ - sizeof(struct_t) + \ - (data->bytes > length_byte ? (sizeof(trailing_type) * data->data[length_byte]) : 0) +/** + * @brief macro to calculate size of message based on struct with member to + * indicate length of dynamic (last) field + * + * @param data cd_s_bin pointer to currently received data + * @param struct_t message struct + * @param length_field struct field with dynamic length + * + * @return size_t with calculated size + * + * equivalent c code: + * + * size_t size = sizeof(struct_t); + * size_t dyn_member_offset = offsetof(struct_t, length_field); + * size_t dyn_member_size = sizeof(((struct_t*)0)->length_field); + * if (data->bytes >= (dyn_member_offset + dyn_member_size)) + * size += cd_bin_ntohd(&data->data[dyn_member_offset], dyn_member_size); + * return size; + */ +#define CD_DYN_MEMBER_SIZEOF(data, struct_t, length_field) \ + sizeof(struct_t) + ( \ + (data->bytes >= (offsetof(struct_t, length_field) + sizeof(((struct_t*)0)->length_field))) ? \ + (cd_bin_ntohd(&data->data[offsetof(struct_t, length_field)], sizeof(((struct_t*)0)->length_field))) :\ + 0); size_t cd_cmd_response_sizeof(cd_s_bin* data) { - (void) data; // unused variable TODO: implement this - return 0; + return CD_DYN_MEMBER_SIZEOF(data, cd_s_cmd_response, response_size); } #ifdef __cplusplus -- cgit v1.2.3 From d8a9d9119df43b163ab6b6799b50f1f04811132a Mon Sep 17 00:00:00 2001 From: lonkaars Date: Mon, 12 Dec 2022 16:20:35 +0100 Subject: serial communication *should* work --- confui/confui.pro | 6 ++- confui/serial.cpp | 47 ++++++++++++++------- shared/pclient.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ shared/pclient.h | 72 ++++++++++++++++++++++++++++++++ shared/protocol.c | 6 +++ shared/protocol.h | 20 ++++++++- 6 files changed, 255 insertions(+), 18 deletions(-) create mode 100644 shared/pclient.c create mode 100644 shared/pclient.h diff --git a/confui/confui.pro b/confui/confui.pro index 023b31c..f73465b 100644 --- a/confui/confui.pro +++ b/confui/confui.pro @@ -12,7 +12,8 @@ SOURCES += \ serial.cpp \ ../shared/bin.c \ ../shared/protocol.c \ - ../shared/serial_parse.c + ../shared/serial_parse.c \ + ../shared/pclient.c HEADERS += \ mainwindow.h \ @@ -27,7 +28,8 @@ HEADERS += \ ../shared/protocol.h \ ../shared/serial_parse.h \ ../shared/consts.h \ - main.h + main.h \ + ../shared/pclient.h CONFIG += c++17 CONFIG += force_debug_info diff --git a/confui/serial.cpp b/confui/serial.cpp index a20ae1c..c03100b 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -1,6 +1,7 @@ #include "serial.h" #include "../shared/serial_parse.h" #include "../shared/bin.h" +#include "../shared/pclient.h" #include #include @@ -34,20 +35,17 @@ void CDSerialConnector::action() { } void CDSerialConnector::write(QByteArray msg) { - _serial->write(msg); - qDebug() << _serial->errorString(); + if (-1 == _serial->write(msg)) + qDebug() << _serial->errorString(); } void CDSerialConnector::connect(string port) { _serial->setPortName(QString::fromStdString(port)); - // QIODevice::ReadOnly - if (!_serial->open(QIODevice::ReadWrite)) qDebug() << _serial->errorString(); + if (!_serial->open(QIODevice::ReadWrite)) + qDebug() << _serial->errorString(); - QObject::connect(_serial, &QSerialPort::readyRead, [&] { - // this is called when readyRead(); - action(); - }); + QObject::connect(_serial, &QSerialPort::readyRead, [&] { action(); }); } void CDSerialConnector::disconnect() { @@ -70,6 +68,17 @@ string CDSerialConnector::get_port() { 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; } @@ -81,17 +90,27 @@ void cd_cmd_ping(cd_s_bin* data) { cd_bin_repl_ntoh16(&cast->id); // fix endianness - std::cout << "ping with id " << cast->id << " received!" << std::endl; + std::cout << "ping request with id " << cast->id << " received!" << std::endl; - // TODO: send ping back + cd_s_bin* response = cd_cmd_res_status((cd_e_scmds) cast->opcode, cast->id, false); + cd_pclient_send(response); + free(response); + response = nullptr; } void cd_cmd_response(cd_s_bin* data) { - (void) data; + CD_CAST_BIN(cd_s_cmd_response, data, cast); - std::cout << "received!" << std::endl; - - return; + cd_bin_repl_ntoh16(&cast->id); + cd_bin_repl_ntoh16(&cast->response_id); + + switch (cast->response_type) { + case CD_CMD_PING: { + std::cout << "ping response with id " << cast->response_id << " received!" << std::endl; + break; + } + default: { } + } } } diff --git a/shared/pclient.c b/shared/pclient.c new file mode 100644 index 0000000..41ace27 --- /dev/null +++ b/shared/pclient.c @@ -0,0 +1,122 @@ +#include + +#include "protocol.h" +#include "pclient.h" +#include "bin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +cd_s_bin* cd_cmd_gen_ping() { + CD_CREATE_MSG_BIN(cd_s_cmd_ping, msg, bin); + + msg->opcode = CD_CMD_PING; + msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); + + return bin; +} + +cd_s_bin* cd_cmd_gen_get_node(bool all, cd_uuid_t uuid) { + CD_CREATE_MSG_BIN(cd_s_cmd_get_node, msg, bin); + + msg->opcode = CD_CMD_GET_NODE; + msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); + msg->all = all; + memcpy(&msg->uuid, &uuid, sizeof(cd_uuid_t)); + + return bin; +} + +cd_s_bin* cd_cmd_gen_post_led(bool on, cd_uuid_t uuid) { + CD_CREATE_MSG_BIN(cd_s_cmd_post_led, msg, bin); + + msg->opcode = CD_CMD_POST_LED; + msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); + msg->on = on; + memcpy(&msg->uuid, &uuid, sizeof(cd_uuid_t)); + + return bin; +} + +cd_s_bin* cd_cmd_gen_post_link_add(cd_uuid_t button, cd_uuid_t light, cd_e_cmd_link_type type) { + CD_CREATE_MSG_BIN(cd_s_cmd_post_link, msg, bin); + + msg->opcode = CD_CMD_POST_LINK; + msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); + msg->add = true; + memcpy(&msg->button, &button, sizeof(cd_uuid_t)); + memcpy(&msg->led, &light, sizeof(cd_uuid_t)); + msg->type = type; + + return bin; +} + +cd_s_bin* cd_cmd_gen_post_link_rm(cd_uuid_t button, cd_uuid_t light) { + CD_CREATE_MSG_BIN(cd_s_cmd_post_link, msg, bin); + + msg->opcode = CD_CMD_POST_LINK; + msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); + msg->add = false; + memcpy(&msg->button, &button, sizeof(cd_uuid_t)); + memcpy(&msg->led, &light, sizeof(cd_uuid_t)); + + return bin; +} + +cd_s_bin* cd_cmd_gen_post_net_add(cd_uuid_t uuid) { + CD_CREATE_MSG_BIN(cd_s_cmd_post_net, msg, bin); + + msg->opcode = CD_CMD_POST_NET; + msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); + msg->join = true; + memcpy(&msg->uuid, &uuid, sizeof(cd_uuid_t)); + + return bin; +} + +cd_s_bin* cd_cmd_gen_post_net_rm(cd_uuid_t uuid) { + CD_CREATE_MSG_BIN(cd_s_cmd_post_net, msg, bin); + + msg->opcode = CD_CMD_POST_NET; + msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); + msg->join = false; + memcpy(&msg->uuid, &uuid, sizeof(cd_uuid_t)); + + return bin; +} + +cd_s_bin* cd_cmd_res_status(cd_e_scmds cmd, cd_cmd_id_t id, bool error) { + CD_CREATE_MSG_BIN(cd_s_cmd_response, msg, bin); + + msg->opcode = CD_CMD_RESPONSE; + msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); + msg->response_type = cmd; + msg->response_id = id; + msg->error = error; + msg->response_size = 0; + + return bin; +} + +cd_s_bin* cd_cmd_res_get_node(cd_e_scmds cmd, cd_cmd_id_t id, uint16_t node_count, cd_s_cmd_node* nodes) { + CD_CREATE_MSG_BIN(cd_s_cmd_response, msg, bin); + + msg->opcode = CD_CMD_RESPONSE; + msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); + msg->response_type = cmd; + msg->response_id = id; + msg->error = false; + + // TODO: test this?? + msg->response_size = sizeof(cd_s_cmd_response_get_node) + sizeof(cd_s_cmd_node) * node_count; + cd_s_cmd_response_get_node* get_node_response_ptr = (cd_s_cmd_response_get_node*) msg->response_info; + memcpy(get_node_response_ptr->nodes, nodes, sizeof(cd_s_cmd_node) * node_count); + + return bin; +} + +#ifdef __cplusplus +} +#endif + diff --git a/shared/pclient.h b/shared/pclient.h new file mode 100644 index 0000000..cf0f182 --- /dev/null +++ b/shared/pclient.h @@ -0,0 +1,72 @@ +#pragma once + +/** @file pclient.h */ + +#include + +#include "protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief send data over platform standard serial out (doesn't free `data`) */ +void cd_pclient_send(cd_s_bin* data); + +/** @brief generate PING command */ +cd_s_bin* cd_cmd_gen_ping(); +/** + * @brief generate GET_NODE command + * @param all get all nodes + * @param uuid get specific node by uuid + */ +cd_s_bin* cd_cmd_gen_get_node(bool all, cd_uuid_t uuid); +/** + * @brief generate POST_LED command + * @param on light status + * @param uuid node to set light of + */ +cd_s_bin* cd_cmd_gen_post_led(bool on, cd_uuid_t uuid); +/** + * @brief generate POST_LINK command to add or update link + * @param button button node uuid + * @param light light node uuid + * @param type type of link to set + */ +cd_s_bin* cd_cmd_gen_post_link_add(cd_uuid_t button, cd_uuid_t light, cd_e_cmd_link_type type); +/** + * @brief generate POST_LINK command to remove link + * @param button button node uuid + * @param light light node uuid + */ +cd_s_bin* cd_cmd_gen_post_link_rm(cd_uuid_t button, cd_uuid_t light); +/** + * @brief generate POST_NET command to provision node into network + * @param uuid node uuid + */ +cd_s_bin* cd_cmd_gen_post_net_add(cd_uuid_t uuid); +/** + * @brief generate POST_NET command to provision node out of network + * @param uuid node uuid + */ +cd_s_bin* cd_cmd_gen_post_net_rm(cd_uuid_t uuid); + +/** + * @brief generate generic RESPONSE command with error field and no response_info + * @param cmd original command opcode + * @param id original command id + * @param error `true` if some error occurred + */ +cd_s_bin* cd_cmd_res_status(cd_e_scmds cmd, cd_cmd_id_t id, bool error); +/** + * @brief generate RESPONSE command with GET_NODE response_info + * @param cmd original command opcode + * @param id original command id + * @param node_count amount of nodes in `nodes` + * @param nodes pointer to array of `cd_s_cmd_node` + */ +cd_s_bin* cd_cmd_res_get_node(cd_e_scmds cmd, cd_cmd_id_t id, uint16_t node_count, cd_s_cmd_node* nodes); + +#ifdef __cplusplus +} +#endif diff --git a/shared/protocol.c b/shared/protocol.c index 1d66f17..fcc0f41 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -6,6 +6,8 @@ extern "C" { #endif +cd_cmd_id_t g_cd_protocol_fresh_message_id = 0; + size_t cd_cmd_sizeof(uint8_t data[CD_SERIAL_READ_BUFFER_SIZE], uint8_t data_length) { cd_cmd_opcode_t opcode = data[0]; if (CD_CMD_HANDLERS_SIZE[opcode] > 0) return CD_CMD_HANDLERS_SIZE[opcode]; @@ -47,6 +49,10 @@ size_t cd_cmd_response_sizeof(cd_s_bin* data) { return CD_DYN_MEMBER_SIZEOF(data, cd_s_cmd_response, response_size); } +cd_cmd_id_t cd_protocol_fresh_message_id() { + return g_cd_protocol_fresh_message_id++; +} + #ifdef __cplusplus } #endif diff --git a/shared/protocol.h b/shared/protocol.h index 7f06a52..63b4a9e 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -29,6 +29,12 @@ typedef uint8_t cd_cmd_bool_t; /** @brief cmd handler function signature */ typedef void (cd_cmd_handler_t)(cd_s_bin *data); +/** @brief used for numbering messages */ +extern cd_cmd_id_t g_cd_protocol_fresh_message_id; + +/** @brief get new message id */ +cd_cmd_id_t cd_protocol_fresh_message_id(); + #pragma pack(push, 1) typedef struct { @@ -50,9 +56,19 @@ typedef struct { cd_uuid_t uuid; /** @brief node uuid to set */ } cd_s_cmd_post_led; +typedef enum { + CD_CMD_LINK_TYPE_TOGGLE = 0x00, + CD_CMD_LINK_TYPE_TURN_ON = 0x01, + CD_CMD_LINK_TYPE_TURN_OFF = 0x02, +} cd_e_cmd_link_type; + typedef struct { cd_cmd_opcode_t opcode; /** @brief cmd opcode */ cd_cmd_id_t id; /** @brief message id */ + cd_uuid_t button; /** @brief uuid of button node */ + cd_uuid_t led; /** @brief uuid of led node */ + cd_cmd_bool_t add; /** @brief `true` to create/overwrite link, `false` to remove link */ + cd_e_cmd_link_type type; /** @brief link type */ } cd_s_cmd_post_link; typedef struct { @@ -80,9 +96,9 @@ typedef struct { typedef struct { cd_cmd_opcode_t opcode; /** @brief cmd opcode */ cd_cmd_id_t id; /** @brief response message id */ - cd_cmd_bool_t success; /** @brief `true` if some error occurred */ - cd_cmd_id_t response_id; /** @brief original message id */ + cd_cmd_bool_t error; /** @brief `true` if some error occurred */ cd_cmd_opcode_t response_type; /** @brief response type, used to cast type of `response_info` */ + cd_cmd_id_t response_id; /** @brief original message id */ uint16_t response_size; /** @brief size of remaining response */ uint8_t response_info[]; /** @brief (CAST) remaining response struct, not read if `response_size`=`0` */ } cd_s_cmd_response; -- cgit v1.2.3 From 9c6c30156aae3bf20a3f1b1d3b0766bb3c924412 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Tue, 13 Dec 2022 14:22:51 +0100 Subject: set correct serial baud rate --- confui/serial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/confui/serial.cpp b/confui/serial.cpp index c03100b..1518abd 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -11,7 +11,7 @@ CDSerialConnector::CDSerialConnector() { this->_serial = new QSerialPort; - if (!_serial->setBaudRate(QSerialPort::Baud9600)) qDebug() << _serial->errorString(); + 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(); -- cgit v1.2.3 From 2c2ff814653f37947f8c253b29f8b08520ae71b7 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Tue, 13 Dec 2022 18:09:23 +0100 Subject: [WIP] node with pub/sub address and uuid --- confui/serial.cpp | 23 +++++++++++++++++++---- shared/bin.h | 2 +- shared/pclient.c | 31 ++++++++++++++++++++++++------- shared/pclient.h | 17 +++++++++++++---- shared/protocol.h | 17 ++++++++++++++++- 5 files changed, 73 insertions(+), 17 deletions(-) diff --git a/confui/serial.cpp b/confui/serial.cpp index 1518abd..09bd7db 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -92,10 +92,25 @@ void cd_cmd_ping(cd_s_bin* data) { 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); - response = nullptr; + // cd_s_bin* response = cd_cmd_res_status((cd_e_scmds) cast->opcode, cast->id, false); + // cd_pclient_send(response); + // free(response); + // response = nullptr; + + cd_uuid_t light_addrs[] = { + { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }, + }; + cd_s_cmd_node* test = cd_cmd_node_alloc({ + .uuid = { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }, + .address = { 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, }, + .light_on = false, + .provisioned = false, + .button_pub = 0xdeadbeef, + }, "gert", 1, light_addrs); + cd_s_bin* testres = cd_cmd_res(CD_CMD_GET_NODE, 0xf88f, test->size, (uint8_t*) test); + cd_pclient_send(testres); + free(testres); + free(test); } void cd_cmd_response(cd_s_bin* data) { diff --git a/shared/bin.h b/shared/bin.h index 0e16ec0..7506655 100644 --- a/shared/bin.h +++ b/shared/bin.h @@ -18,7 +18,7 @@ extern "C" { extern uint8_t g_cd_endianness; -/** cast `in.data` to `type out` */ +/** @brief cast `in.data` to `type out` */ #define CD_CAST_BIN(type, in, out) type *out = (type *)&in->data; #define CD_CREATE_MSG_BIN(type, normal, bin) CD_CREATE_MSG_SIZE_BIN(type, sizeof(type), normal, bin) /** @brief */ diff --git a/shared/pclient.c b/shared/pclient.c index 41ace27..0464428 100644 --- a/shared/pclient.c +++ b/shared/pclient.c @@ -99,23 +99,40 @@ cd_s_bin* cd_cmd_res_status(cd_e_scmds cmd, cd_cmd_id_t id, bool error) { return bin; } -cd_s_bin* cd_cmd_res_get_node(cd_e_scmds cmd, cd_cmd_id_t id, uint16_t node_count, cd_s_cmd_node* nodes) { - CD_CREATE_MSG_BIN(cd_s_cmd_response, msg, bin); +cd_s_bin* cd_cmd_res(cd_e_scmds cmd, cd_cmd_id_t id, uint16_t len, uint8_t* data) { + CD_CREATE_MSG_SIZE_BIN(cd_s_cmd_response, sizeof(cd_s_cmd_response) + len, msg, bin); msg->opcode = CD_CMD_RESPONSE; msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); msg->response_type = cmd; msg->response_id = id; msg->error = false; - - // TODO: test this?? - msg->response_size = sizeof(cd_s_cmd_response_get_node) + sizeof(cd_s_cmd_node) * node_count; - cd_s_cmd_response_get_node* get_node_response_ptr = (cd_s_cmd_response_get_node*) msg->response_info; - memcpy(get_node_response_ptr->nodes, nodes, sizeof(cd_s_cmd_node) * node_count); + msg->response_size = len; + memcpy(msg->response_info, data, len); return bin; } +cd_s_cmd_node* cd_cmd_node_alloc(cd_s_cmd_node base, const char* name, uint16_t link_count, cd_uuid_t* links) { + size_t name_len = strlen(name); + size_t links_len = sizeof(cd_uuid_t) * link_count; + size_t size = sizeof(cd_s_cmd_node) + sizeof(char) * name_len + links_len; + cd_s_cmd_node* node = malloc(size); + + memcpy(&node->uuid, &base.uuid, sizeof(cd_uuid_t)); + memcpy(&node->address, &base.address, sizeof(cd_mac_addr_t)); + node->name_len = name_len; + node->light_on = base.light_on; + node->provisioned = base.provisioned; + node->button_pub = cd_bin_hton32(base.button_pub); + node->link_count = cd_bin_hton16(link_count); + node->size = cd_bin_hton16(size); + memcpy((void *)&node->data_remainder, name, name_len); // copy name + memcpy((void *)&node->data_remainder + name_len, links, links_len); // copy links + + return node; +} + #ifdef __cplusplus } #endif diff --git a/shared/pclient.h b/shared/pclient.h index cf0f182..d0ddeb7 100644 --- a/shared/pclient.h +++ b/shared/pclient.h @@ -59,13 +59,22 @@ cd_s_bin* cd_cmd_gen_post_net_rm(cd_uuid_t uuid); */ cd_s_bin* cd_cmd_res_status(cd_e_scmds cmd, cd_cmd_id_t id, bool error); /** - * @brief generate RESPONSE command with GET_NODE response_info + * @brief generate RESPONSE command with response_info * @param cmd original command opcode * @param id original command id - * @param node_count amount of nodes in `nodes` - * @param nodes pointer to array of `cd_s_cmd_node` + * @param len size of `data` in bytes + * @param data pointer to data */ -cd_s_bin* cd_cmd_res_get_node(cd_e_scmds cmd, cd_cmd_id_t id, uint16_t node_count, cd_s_cmd_node* nodes); +cd_s_bin* cd_cmd_res(cd_e_scmds cmd, cd_cmd_id_t id, uint16_t len, uint8_t* data); +/** + * @brief allocate and fill cd_s_cmd_node struct + * + * @param base base struct with values that can be initialized using an initialization list + * @param name node name (length is calculated at runtime using strlen()) + * @param link_count amount of lights this node controls + * @param links array of light node uuids + */ +cd_s_cmd_node* cd_cmd_node_alloc(cd_s_cmd_node base, const char* name, uint16_t link_count, cd_uuid_t* links); #ifdef __cplusplus } diff --git a/shared/protocol.h b/shared/protocol.h index 63b4a9e..6f9697f 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -19,6 +19,9 @@ typedef uint8_t cd_mac_addr_t[6]; /** @brief uuid (ffeeddcc-bbaa-9988-7766-554433221100) */ typedef uint8_t cd_uuid_t[16]; +/** @brief pub/sub address type */ +typedef uint32_t cd_mesh_psub_addr; + /** @brief command opcode (identifies message type) */ typedef uint8_t cd_cmd_opcode_t; /** @brief command id (identifies messages uniquely) */ @@ -85,7 +88,19 @@ typedef struct { uint8_t name_len; /** @brief name length in bytes */ cd_cmd_bool_t light_on; /** @brief state of light on node */ cd_cmd_bool_t provisioned; /** @brief whether the node is provisioned into the network */ - const char name[]; /** @brief user-friendly node name */ + cd_mesh_psub_addr button_pub; /** @brief button publish address */ + uint16_t link_count; /** @brief amount of addresses to publish button press to */ + uint16_t size; /** @brief calculated size for convenience */ + const uint8_t data_remainder[]; /** + * @brief remaining data (name and link array) + * + * this data is stored adjacently in memory + * and is cast when reading/writing this + * struct + * + * 1. char[] name + * 2. cd_uuid_t[] light_publish_addresses; + */ } cd_s_cmd_node; typedef struct { -- cgit v1.2.3 From f24da35b75c46df8af41514aa4c11e0b9b7ed162 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Tue, 13 Dec 2022 21:50:03 +0100 Subject: add binary files as text with comments and makefile --- shared/protocol-tests/.gitignore | 1 + shared/protocol-tests/makefile | 15 +++++++++++++++ shared/protocol-tests/ping-response.bin | Bin 10 -> 0 bytes shared/protocol-tests/ping-response.src | 10 ++++++++++ shared/protocol-tests/ping.bin | Bin 4 -> 0 bytes shared/protocol-tests/ping.src | 4 ++++ 6 files changed, 30 insertions(+) create mode 100644 shared/protocol-tests/.gitignore create mode 100644 shared/protocol-tests/makefile delete mode 100644 shared/protocol-tests/ping-response.bin create mode 100644 shared/protocol-tests/ping-response.src delete mode 100644 shared/protocol-tests/ping.bin create mode 100644 shared/protocol-tests/ping.src diff --git a/shared/protocol-tests/.gitignore b/shared/protocol-tests/.gitignore new file mode 100644 index 0000000..a8a0dce --- /dev/null +++ b/shared/protocol-tests/.gitignore @@ -0,0 +1 @@ +*.bin diff --git a/shared/protocol-tests/makefile b/shared/protocol-tests/makefile new file mode 100644 index 0000000..f8ac490 --- /dev/null +++ b/shared/protocol-tests/makefile @@ -0,0 +1,15 @@ +XXD := xxd +RM := rm -f + +SRCS := $(wildcard *.src) +TARGET := $(SRCS:.src=.bin) + +.PHONY: all clean + +all: $(TARGET) + +%.bin: %.src + $(XXD) -r -c1 $< $@ + +clean: + $(RM) $(TARGET) diff --git a/shared/protocol-tests/ping-response.bin b/shared/protocol-tests/ping-response.bin deleted file mode 100644 index 6067349..0000000 Binary files a/shared/protocol-tests/ping-response.bin and /dev/null differ diff --git a/shared/protocol-tests/ping-response.src b/shared/protocol-tests/ping-response.src new file mode 100644 index 0000000..57418d5 --- /dev/null +++ b/shared/protocol-tests/ping-response.src @@ -0,0 +1,10 @@ +00: ff ; start byte +01: 05 ; response opcode +02: 00 ; message id (0x0001) +03: 01 ; ^ +04: 01 ; error (true) +05: 00 ; response type (0x00 = ping) +06: 00 ; original message id (0x0000) +07: 00 ; ^ +08: 00 ; remainder size (0x0000) +09: 00 ; ^ diff --git a/shared/protocol-tests/ping.bin b/shared/protocol-tests/ping.bin deleted file mode 100644 index 2b8491c..0000000 Binary files a/shared/protocol-tests/ping.bin and /dev/null differ diff --git a/shared/protocol-tests/ping.src b/shared/protocol-tests/ping.src new file mode 100644 index 0000000..beec10a --- /dev/null +++ b/shared/protocol-tests/ping.src @@ -0,0 +1,4 @@ +00: ff ; start byte +01: 00 ; ping opcode +02: f8 ; message id (used as ping identifier) +03: 8f ; ^ -- cgit v1.2.3 From 4e4b35df42044c0f72a6f50a7f0158db4f379748 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Thu, 5 Jan 2023 13:51:33 +0100 Subject: fix `cd_s_cmd_node` alloc/create function --- confui/makefile | 3 +++ confui/serial.cpp | 9 +++++---- shared/pclient.c | 18 ++++++++++-------- shared/pclient.h | 4 +++- shared/protocol.h | 4 ++-- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/confui/makefile b/confui/makefile index e1faed6..2e22e20 100644 --- a/confui/makefile +++ b/confui/makefile @@ -18,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/serial.cpp b/confui/serial.cpp index 09bd7db..c0e686b 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -100,17 +100,18 @@ void cd_cmd_ping(cd_s_bin* data) { cd_uuid_t light_addrs[] = { { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }, }; - cd_s_cmd_node* test = cd_cmd_node_alloc({ + cd_s_cmd_node* test = cd_cmd_node_alloc("gert", { .uuid = { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }, .address = { 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, }, .light_on = false, .provisioned = false, .button_pub = 0xdeadbeef, - }, "gert", 1, light_addrs); - cd_s_bin* testres = cd_cmd_res(CD_CMD_GET_NODE, 0xf88f, test->size, (uint8_t*) test); + }, 1, light_addrs); + cd_s_bin* testres = cd_cmd_res(CD_CMD_GET_NODE, 0xf88f, cd_cmd_node_sizeof(test), (uint8_t*) test); + free(test); + cd_pclient_send(testres); free(testres); - free(test); } void cd_cmd_response(cd_s_bin* data) { diff --git a/shared/pclient.c b/shared/pclient.c index 0464428..be0e0a7 100644 --- a/shared/pclient.c +++ b/shared/pclient.c @@ -107,17 +107,17 @@ cd_s_bin* cd_cmd_res(cd_e_scmds cmd, cd_cmd_id_t id, uint16_t len, uint8_t* data msg->response_type = cmd; msg->response_id = id; msg->error = false; - msg->response_size = len; + msg->response_size = cd_bin_hton16(len); memcpy(msg->response_info, data, len); return bin; } -cd_s_cmd_node* cd_cmd_node_alloc(cd_s_cmd_node base, const char* name, uint16_t link_count, cd_uuid_t* links) { +cd_s_cmd_node* cd_cmd_node_alloc(const char* name, cd_s_cmd_node base, uint16_t link_count, cd_uuid_t* links) { size_t name_len = strlen(name); - size_t links_len = sizeof(cd_uuid_t) * link_count; - size_t size = sizeof(cd_s_cmd_node) + sizeof(char) * name_len + links_len; - cd_s_cmd_node* node = malloc(size); + size_t links_size = sizeof(cd_uuid_t) * link_count; + size_t remaining_size = sizeof(char) * name_len + links_size; + cd_s_cmd_node* node = malloc(sizeof(cd_s_cmd_node) + remaining_size); memcpy(&node->uuid, &base.uuid, sizeof(cd_uuid_t)); memcpy(&node->address, &base.address, sizeof(cd_mac_addr_t)); @@ -126,9 +126,11 @@ cd_s_cmd_node* cd_cmd_node_alloc(cd_s_cmd_node base, const char* name, uint16_t node->provisioned = base.provisioned; node->button_pub = cd_bin_hton32(base.button_pub); node->link_count = cd_bin_hton16(link_count); - node->size = cd_bin_hton16(size); - memcpy((void *)&node->data_remainder, name, name_len); // copy name - memcpy((void *)&node->data_remainder + name_len, links, links_len); // copy links + node->remaining_size = cd_bin_hton16(remaining_size); + void* cursor = (void*) &node->remaining_data[0]; + memcpy(cursor, name, name_len); // copy name + cursor += name_len; + memcpy(cursor, links, links_size); // copy links return node; } diff --git a/shared/pclient.h b/shared/pclient.h index d0ddeb7..e1bb7e7 100644 --- a/shared/pclient.h +++ b/shared/pclient.h @@ -74,7 +74,9 @@ cd_s_bin* cd_cmd_res(cd_e_scmds cmd, cd_cmd_id_t id, uint16_t len, uint8_t* data * @param link_count amount of lights this node controls * @param links array of light node uuids */ -cd_s_cmd_node* cd_cmd_node_alloc(cd_s_cmd_node base, const char* name, uint16_t link_count, cd_uuid_t* links); +cd_s_cmd_node* cd_cmd_node_alloc(const char* name, cd_s_cmd_node base, uint16_t link_count, cd_uuid_t* links); + +#define cd_cmd_node_sizeof(node) ((sizeof(cd_s_cmd_node) + cd_bin_ntoh16(node->remaining_size)) /* NOLINT */) #ifdef __cplusplus } diff --git a/shared/protocol.h b/shared/protocol.h index 6f9697f..dd5bcc6 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -90,8 +90,8 @@ typedef struct { cd_cmd_bool_t provisioned; /** @brief whether the node is provisioned into the network */ cd_mesh_psub_addr button_pub; /** @brief button publish address */ uint16_t link_count; /** @brief amount of addresses to publish button press to */ - uint16_t size; /** @brief calculated size for convenience */ - const uint8_t data_remainder[]; /** + uint16_t remaining_size; /** @brief calculated size of remaining_data for convenience */ + const uint8_t remaining_data[]; /** * @brief remaining data (name and link array) * * this data is stored adjacently in memory -- cgit v1.2.3 From 3fc0e63e43c0de9ecbc084e7f7710716ac88cf51 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Thu, 5 Jan 2023 14:10:38 +0100 Subject: get-node-response v1 added --- shared/protocol-tests/get-node-response.src | 76 +++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 shared/protocol-tests/get-node-response.src diff --git a/shared/protocol-tests/get-node-response.src b/shared/protocol-tests/get-node-response.src new file mode 100644 index 0000000..a8fa695 --- /dev/null +++ b/shared/protocol-tests/get-node-response.src @@ -0,0 +1,76 @@ +00: ff ; start byte +01: 05 ; opcode (0x05 = response) +02: 00 ; message id (0x0000) +03: 00 ; ^ +04: 00 ; error byte (0x00 = false) +05: 01 ; response type (0x01 = get node) +06: 8f ; original message id (0x8ff8) +07: f8 ; ^ +08: 00 ; remaining response size (0x35 = 53 bytes) +09: 35 ; ^ +-------; |- remaining response (cd_s_cmd_node) +0a: ff ; | [esc] +0b: ff ; | uuid (ffffffff-0000-0000-dead-beef00000000) +0c: ff ; | [esc] +0d: ff ; | ^ +0e: ff ; | [esc] +0f: ff ; | ^ +10: ff ; | [esc] +11: ff ; | ^ +12: 00 ; | ^ +13: 00 ; | ^ +14: 00 ; | ^ +15: 00 ; | ^ +16: de ; | ^ +17: ad ; | ^ +18: be ; | ^ +19: ef ; | ^ +1a: 00 ; | ^ +1b: 00 ; | ^ +1c: 00 ; | ^ +1d: 00 ; | ^ +1e: ff ; | [esc] +1f: ff ; | mac address (ff:00:ff:00:ff:00) +20: 00 ; | ^ +21: ff ; | [esc] +22: ff ; | ^ +23: 00 ; | ^ +24: ff ; | [esc] +25: ff ; | ^ +26: 00 ; | ^ +27: 04 ; | name length (0x04 = 4) +28: 00 ; | light on (0x00 = false) +29: 00 ; | provisioned (0x00 = false) +2a: de ; | button publish address (0xdeadbeef) +2b: ad ; | ^ +2c: be ; | ^ +2d: ef ; | ^ +2e: 00 ; | link count (0x0001 = 1) +2f: 01 ; | ^ +30: 00 ; | remaining size (0x14 = 20 bytes) +31: 14 ; | ^ +-------; | |- remaining response (char[4], cd_uuid_t[1]) +32: 67 ; | | node name ("gert") +33: 65 ; | | ^ +34: 72 ; | | ^ +35: 74 ; | | ^ +36: ff ; | | [esc] +37: ff ; | | link[0] uuid (ffffffff-0000-0000-dead-beef00000000) +38: ff ; | | [esc] +39: ff ; | | ^ +3a: ff ; | | [esc] +3b: ff ; | | ^ +3c: ff ; | | [esc] +3d: ff ; | | ^ +3e: 00 ; | | ^ +3f: 00 ; | | ^ +40: 00 ; | | ^ +41: 00 ; | | ^ +42: de ; | | ^ +43: ad ; | | ^ +44: be ; | | ^ +45: ef ; | | ^ +46: 00 ; | | ^ +47: 00 ; | | ^ +48: 00 ; | | ^ +49: 00 ; | | ^ -- cgit v1.2.3 From 8294ed270bce6b563efc1859a8049e018818e1be Mon Sep 17 00:00:00 2001 From: lonkaars Date: Thu, 5 Jan 2023 14:30:24 +0100 Subject: proper protocol spec get-node response --- shared/protocol-tests/get-node-response.src | 135 ++++++++++++++-------------- 1 file changed, 69 insertions(+), 66 deletions(-) diff --git a/shared/protocol-tests/get-node-response.src b/shared/protocol-tests/get-node-response.src index a8fa695..f10ffe0 100644 --- a/shared/protocol-tests/get-node-response.src +++ b/shared/protocol-tests/get-node-response.src @@ -8,69 +8,72 @@ 07: f8 ; ^ 08: 00 ; remaining response size (0x35 = 53 bytes) 09: 35 ; ^ --------; |- remaining response (cd_s_cmd_node) -0a: ff ; | [esc] -0b: ff ; | uuid (ffffffff-0000-0000-dead-beef00000000) -0c: ff ; | [esc] -0d: ff ; | ^ -0e: ff ; | [esc] -0f: ff ; | ^ -10: ff ; | [esc] -11: ff ; | ^ -12: 00 ; | ^ -13: 00 ; | ^ -14: 00 ; | ^ -15: 00 ; | ^ -16: de ; | ^ -17: ad ; | ^ -18: be ; | ^ -19: ef ; | ^ -1a: 00 ; | ^ -1b: 00 ; | ^ -1c: 00 ; | ^ -1d: 00 ; | ^ -1e: ff ; | [esc] -1f: ff ; | mac address (ff:00:ff:00:ff:00) -20: 00 ; | ^ -21: ff ; | [esc] -22: ff ; | ^ -23: 00 ; | ^ -24: ff ; | [esc] -25: ff ; | ^ -26: 00 ; | ^ -27: 04 ; | name length (0x04 = 4) -28: 00 ; | light on (0x00 = false) -29: 00 ; | provisioned (0x00 = false) -2a: de ; | button publish address (0xdeadbeef) -2b: ad ; | ^ -2c: be ; | ^ -2d: ef ; | ^ -2e: 00 ; | link count (0x0001 = 1) -2f: 01 ; | ^ -30: 00 ; | remaining size (0x14 = 20 bytes) -31: 14 ; | ^ --------; | |- remaining response (char[4], cd_uuid_t[1]) -32: 67 ; | | node name ("gert") -33: 65 ; | | ^ -34: 72 ; | | ^ -35: 74 ; | | ^ -36: ff ; | | [esc] -37: ff ; | | link[0] uuid (ffffffff-0000-0000-dead-beef00000000) -38: ff ; | | [esc] -39: ff ; | | ^ -3a: ff ; | | [esc] -3b: ff ; | | ^ -3c: ff ; | | [esc] -3d: ff ; | | ^ -3e: 00 ; | | ^ -3f: 00 ; | | ^ -40: 00 ; | | ^ -41: 00 ; | | ^ -42: de ; | | ^ -43: ad ; | | ^ -44: be ; | | ^ -45: ef ; | | ^ -46: 00 ; | | ^ -47: 00 ; | | ^ -48: 00 ; | | ^ -49: 00 ; | | ^ +-------; |- remaining response (cd_s_cmd_response_get_node) +0a: 00 ; | node count (0x0001 = 1) +0b: 01 ; | ^ +-------; | |- remaining response (cd_s_cmd_node[1]) +0c: ff ; | | [esc] +0d: ff ; | | uuid (ffffffff-0000-0000-dead-beef00000000) +0e: ff ; | | [esc] +0f: ff ; | | ^ +10: ff ; | | [esc] +11: ff ; | | ^ +12: ff ; | | [esc] +13: ff ; | | ^ +14: 00 ; | | ^ +15: 00 ; | | ^ +16: 00 ; | | ^ +17: 00 ; | | ^ +18: de ; | | ^ +19: ad ; | | ^ +1a: be ; | | ^ +1b: ef ; | | ^ +1c: 00 ; | | ^ +1d: 00 ; | | ^ +1e: 00 ; | | ^ +1f: 00 ; | | ^ +20: ff ; | | [esc] +21: ff ; | | mac address (ff:00:ff:00:ff:00) +22: 00 ; | | ^ +23: ff ; | | [esc] +24: ff ; | | ^ +25: 00 ; | | ^ +26: ff ; | | [esc] +27: ff ; | | ^ +28: 00 ; | | ^ +29: 04 ; | | name length (0x04 = 4) +2a: 00 ; | | light on (0x00 = false) +2b: 00 ; | | provisioned (0x00 = false) +2c: de ; | | button publish address (0xdeadbeef) +2d: ad ; | | ^ +2e: be ; | | ^ +2f: ef ; | | ^ +30: 00 ; | | link count (0x0001 = 1) +31: 01 ; | | ^ +32: 00 ; | | remaining size (0x14 = 20 bytes) +33: 14 ; | | ^ +-------; | | |- remaining response (char[4], cd_uuid_t[1]) +34: 67 ; | | | node name ("gert") +35: 65 ; | | | ^ +36: 72 ; | | | ^ +37: 74 ; | | | ^ +38: ff ; | | | [esc] +39: ff ; | | | link[0] uuid (ffffffff-0000-0000-dead-beef00000000) +3a: ff ; | | | [esc] +3b: ff ; | | | ^ +3c: ff ; | | | [esc] +3d: ff ; | | | ^ +3e: ff ; | | | [esc] +3f: ff ; | | | ^ +40: 00 ; | | | ^ +41: 00 ; | | | ^ +42: 00 ; | | | ^ +43: 00 ; | | | ^ +44: de ; | | | ^ +45: ad ; | | | ^ +46: be ; | | | ^ +47: ef ; | | | ^ +48: 00 ; | | | ^ +49: 00 ; | | | ^ +4a: 00 ; | | | ^ +4b: 00 ; | | | ^ -- cgit v1.2.3 From 759d73e4ef0167c654535637488bdfcd423015a0 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Thu, 5 Jan 2023 15:03:58 +0100 Subject: improve parseability of get-nodes response --- confui/serial.cpp | 19 +++--- shared/pclient.c | 21 +++++++ shared/pclient.h | 10 ++- shared/protocol-tests/get-node-response.src | 98 +++++++++++++++-------------- shared/protocol.h | 5 +- 5 files changed, 95 insertions(+), 58 deletions(-) diff --git a/confui/serial.cpp b/confui/serial.cpp index c0e686b..dd2a702 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -97,21 +97,26 @@ void cd_cmd_ping(cd_s_bin* data) { // free(response); // response = nullptr; - cd_uuid_t light_addrs[] = { + cd_uuid_t test_node_light_addrs[] = { { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }, }; - cd_s_cmd_node* test = cd_cmd_node_alloc("gert", { + cd_s_cmd_node* test_node = cd_cmd_node_alloc("gert", { .uuid = { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }, .address = { 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, }, .light_on = false, .provisioned = false, .button_pub = 0xdeadbeef, - }, 1, light_addrs); - cd_s_bin* testres = cd_cmd_res(CD_CMD_GET_NODE, 0xf88f, cd_cmd_node_sizeof(test), (uint8_t*) test); - free(test); + }, 1, test_node_light_addrs); - cd_pclient_send(testres); - free(testres); + cd_s_cmd_node* nodes[] = { test_node }; + cd_s_cmd_response_get_node* response_get_nodes = cd_cmd_get_node_res_from_node_arr(1, nodes); + free(test_node); + + cd_s_bin* response = cd_cmd_res(CD_CMD_GET_NODE, 0xf88f, cd_cmd_response_get_node_sizeof(response_get_nodes), (uint8_t*) response_get_nodes); + free(response_get_nodes); + + cd_pclient_send(response); + free(response); } void cd_cmd_response(cd_s_bin* data) { diff --git a/shared/pclient.c b/shared/pclient.c index be0e0a7..728bfa0 100644 --- a/shared/pclient.c +++ b/shared/pclient.c @@ -135,6 +135,27 @@ cd_s_cmd_node* cd_cmd_node_alloc(const char* name, cd_s_cmd_node base, uint16_t return node; } +cd_s_cmd_response_get_node* cd_cmd_get_node_res_from_node_arr(uint16_t size, cd_s_cmd_node* arr[]) { + size_t remaining_size = 0; + + for (unsigned int i = 0; i < size; i++) { + remaining_size += sizeof(cd_s_cmd_node) + cd_bin_ntoh16(arr[i]->remaining_size); + } + + cd_s_cmd_response_get_node* response = malloc(sizeof(cd_s_cmd_response_get_node) + remaining_size); + response->node_count = cd_bin_hton16(size); + response->remaining_size = cd_bin_hton16(remaining_size); + + void* cursor = response->nodes; + for (unsigned int i = 0; i < size; i++) { + size_t size = sizeof(cd_s_cmd_node) + cd_bin_ntoh16(arr[i]->remaining_size); + memcpy(cursor, arr[i], size); + cursor += size; + } + + return response; +} + #ifdef __cplusplus } #endif diff --git a/shared/pclient.h b/shared/pclient.h index e1bb7e7..03a8a25 100644 --- a/shared/pclient.h +++ b/shared/pclient.h @@ -66,6 +66,12 @@ cd_s_bin* cd_cmd_res_status(cd_e_scmds cmd, cd_cmd_id_t id, bool error); * @param data pointer to data */ cd_s_bin* cd_cmd_res(cd_e_scmds cmd, cd_cmd_id_t id, uint16_t len, uint8_t* data); +/** + * @brief generate cd_s_cmd_response_get_node struct from array of cd_s_cmd_node pointers + * @param size length of array + * @param arr array of pointer to cd_s_cmd_node + */ +cd_s_cmd_response_get_node* cd_cmd_get_node_res_from_node_arr(uint16_t size, cd_s_cmd_node* arr[]); /** * @brief allocate and fill cd_s_cmd_node struct * @@ -76,7 +82,9 @@ cd_s_bin* cd_cmd_res(cd_e_scmds cmd, cd_cmd_id_t id, uint16_t len, uint8_t* data */ cd_s_cmd_node* cd_cmd_node_alloc(const char* name, cd_s_cmd_node base, uint16_t link_count, cd_uuid_t* links); -#define cd_cmd_node_sizeof(node) ((sizeof(cd_s_cmd_node) + cd_bin_ntoh16(node->remaining_size)) /* NOLINT */) +#define cd_remaining_sizeof(type, input_struct) ((sizeof(type) + cd_bin_ntoh16(input_struct->remaining_size)) /* NOLINT */) +#define cd_cmd_node_sizeof(node) (cd_remaining_sizeof(cd_s_cmd_node, node) /* NOLINT */) +#define cd_cmd_response_get_node_sizeof(res) (cd_remaining_sizeof(cd_s_cmd_response_get_node, res) /* NOLINT */) #ifdef __cplusplus } diff --git a/shared/protocol-tests/get-node-response.src b/shared/protocol-tests/get-node-response.src index f10ffe0..31bf1ff 100644 --- a/shared/protocol-tests/get-node-response.src +++ b/shared/protocol-tests/get-node-response.src @@ -6,74 +6,76 @@ 05: 01 ; response type (0x01 = get node) 06: 8f ; original message id (0x8ff8) 07: f8 ; ^ -08: 00 ; remaining response size (0x35 = 53 bytes) -09: 35 ; ^ +08: 00 ; remaining response size (0x39 = 57 bytes) +09: 39 ; ^ -------; |- remaining response (cd_s_cmd_response_get_node) 0a: 00 ; | node count (0x0001 = 1) 0b: 01 ; | ^ +0c: 00 ; | remaining response size (0x35 = 53 bytes) +0d: 35 ; | ^ -------; | |- remaining response (cd_s_cmd_node[1]) -0c: ff ; | | [esc] -0d: ff ; | | uuid (ffffffff-0000-0000-dead-beef00000000) 0e: ff ; | | [esc] -0f: ff ; | | ^ +0f: ff ; | | uuid (ffffffff-0000-0000-dead-beef00000000) 10: ff ; | | [esc] 11: ff ; | | ^ 12: ff ; | | [esc] 13: ff ; | | ^ -14: 00 ; | | ^ -15: 00 ; | | ^ +14: ff ; | | [esc] +15: ff ; | | ^ 16: 00 ; | | ^ 17: 00 ; | | ^ -18: de ; | | ^ -19: ad ; | | ^ -1a: be ; | | ^ -1b: ef ; | | ^ -1c: 00 ; | | ^ -1d: 00 ; | | ^ +18: 00 ; | | ^ +19: 00 ; | | ^ +1a: de ; | | ^ +1b: ad ; | | ^ +1c: be ; | | ^ +1d: ef ; | | ^ 1e: 00 ; | | ^ 1f: 00 ; | | ^ -20: ff ; | | [esc] -21: ff ; | | mac address (ff:00:ff:00:ff:00) -22: 00 ; | | ^ -23: ff ; | | [esc] -24: ff ; | | ^ -25: 00 ; | | ^ -26: ff ; | | [esc] -27: ff ; | | ^ -28: 00 ; | | ^ -29: 04 ; | | name length (0x04 = 4) -2a: 00 ; | | light on (0x00 = false) -2b: 00 ; | | provisioned (0x00 = false) -2c: de ; | | button publish address (0xdeadbeef) -2d: ad ; | | ^ -2e: be ; | | ^ -2f: ef ; | | ^ -30: 00 ; | | link count (0x0001 = 1) -31: 01 ; | | ^ -32: 00 ; | | remaining size (0x14 = 20 bytes) -33: 14 ; | | ^ +20: 00 ; | | ^ +21: 00 ; | | ^ +22: ff ; | | [esc] +23: ff ; | | mac address (ff:00:ff:00:ff:00) +24: 00 ; | | ^ +25: ff ; | | [esc] +26: ff ; | | ^ +27: 00 ; | | ^ +28: ff ; | | [esc] +29: ff ; | | ^ +2a: 00 ; | | ^ +2b: 04 ; | | name length (0x04 = 4) +2c: 00 ; | | light on (0x00 = false) +2d: 00 ; | | provisioned (0x00 = false) +2e: de ; | | button publish address (0xdeadbeef) +2f: ad ; | | ^ +30: be ; | | ^ +31: ef ; | | ^ +32: 00 ; | | link count (0x0001 = 1) +33: 01 ; | | ^ +34: 00 ; | | remaining size (0x14 = 20 bytes) +35: 14 ; | | ^ -------; | | |- remaining response (char[4], cd_uuid_t[1]) -34: 67 ; | | | node name ("gert") -35: 65 ; | | | ^ -36: 72 ; | | | ^ -37: 74 ; | | | ^ -38: ff ; | | | [esc] -39: ff ; | | | link[0] uuid (ffffffff-0000-0000-dead-beef00000000) +36: 67 ; | | | node name ("gert") +37: 65 ; | | | ^ +38: 72 ; | | | ^ +39: 74 ; | | | ^ 3a: ff ; | | | [esc] -3b: ff ; | | | ^ +3b: ff ; | | | link[0] uuid (ffffffff-0000-0000-dead-beef00000000) 3c: ff ; | | | [esc] 3d: ff ; | | | ^ 3e: ff ; | | | [esc] 3f: ff ; | | | ^ -40: 00 ; | | | ^ -41: 00 ; | | | ^ +40: ff ; | | | [esc] +41: ff ; | | | ^ 42: 00 ; | | | ^ 43: 00 ; | | | ^ -44: de ; | | | ^ -45: ad ; | | | ^ -46: be ; | | | ^ -47: ef ; | | | ^ -48: 00 ; | | | ^ -49: 00 ; | | | ^ +44: 00 ; | | | ^ +45: 00 ; | | | ^ +46: de ; | | | ^ +47: ad ; | | | ^ +48: be ; | | | ^ +49: ef ; | | | ^ 4a: 00 ; | | | ^ 4b: 00 ; | | | ^ +4c: 00 ; | | | ^ +4d: 00 ; | | | ^ diff --git a/shared/protocol.h b/shared/protocol.h index dd5bcc6..cad9a1c 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -104,8 +104,9 @@ typedef struct { } cd_s_cmd_node; typedef struct { - uint16_t node_count; - cd_s_cmd_node nodes[]; + uint16_t node_count; /** amount of nodes in nodes[] */ + uint16_t remaining_size; /** remaining size (for convenience) */ + cd_s_cmd_node nodes[]; /** nodes adjacent in memory (should be accessed using pointer arithmetic) */ } cd_s_cmd_response_get_node; typedef struct { -- cgit v1.2.3 From c3dcee6a94032904c03a4f7daec98fdc81ea2357 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Thu, 5 Jan 2023 15:41:19 +0100 Subject: WIP get node response parsing on gui --- confui/mesh_connector.cpp | 40 +++++++++++----------- confui/serial.cpp | 87 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 80 insertions(+), 47 deletions(-) diff --git a/confui/mesh_connector.cpp b/confui/mesh_connector.cpp index fd9c5fc..b7991b7 100644 --- a/confui/mesh_connector.cpp +++ b/confui/mesh_connector.cpp @@ -16,26 +16,26 @@ 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; } diff --git a/confui/serial.cpp b/confui/serial.cpp index dd2a702..c972ffb 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -92,31 +92,66 @@ void cd_cmd_ping(cd_s_bin* data) { 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_s_bin* response = cd_cmd_res_status((cd_e_scmds) cast->opcode, cast->id, false); + cd_pclient_send(response); + free(response); + response = nullptr; + + // cd_uuid_t test_node_light_addrs[] = { + // { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }, + // }; + // cd_s_cmd_node* test_node = cd_cmd_node_alloc("gert", { + // .uuid = { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }, + // .address = { 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, }, + // .light_on = false, + // .provisioned = false, + // .button_pub = 0xdeadbeef, + // }, 1, test_node_light_addrs); + + // cd_s_cmd_node* nodes[] = { test_node }; + // cd_s_cmd_response_get_node* response_get_nodes = cd_cmd_get_node_res_from_node_arr(1, nodes); + // free(test_node); + + // cd_s_bin* response = cd_cmd_res(CD_CMD_GET_NODE, 0xf88f, cd_cmd_response_get_node_sizeof(response_get_nodes), (uint8_t*) response_get_nodes); + // free(response_get_nodes); + // cd_pclient_send(response); // free(response); - // response = nullptr; - - cd_uuid_t test_node_light_addrs[] = { - { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }, - }; - cd_s_cmd_node* test_node = cd_cmd_node_alloc("gert", { - .uuid = { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }, - .address = { 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, }, - .light_on = false, - .provisioned = false, - .button_pub = 0xdeadbeef, - }, 1, test_node_light_addrs); - - cd_s_cmd_node* nodes[] = { test_node }; - cd_s_cmd_response_get_node* response_get_nodes = cd_cmd_get_node_res_from_node_arr(1, nodes); - free(test_node); - - cd_s_bin* response = cd_cmd_res(CD_CMD_GET_NODE, 0xf88f, cd_cmd_response_get_node_sizeof(response_get_nodes), (uint8_t*) response_get_nodes); - free(response_get_nodes); +} - 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"); + // WIP + // cd_gui_node_id_t id = get_or_create_id(node->uuid); + // node* gui_node = g_cd_mesh_connector->get_node(id); + // (fill gui_node) + // (refresh gui) +} + +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(cd_s_bin* data) { @@ -126,11 +161,9 @@ void cd_cmd_response(cd_s_bin* data) { cd_bin_repl_ntoh16(&cast->response_id); switch (cast->response_type) { - case CD_CMD_PING: { - std::cout << "ping response with id " << cast->response_id << " received!" << std::endl; - break; - } - default: { } + case CD_CMD_PING: return cd_cmd_response_ping(data); + case CD_CMD_GET_NODE: return cd_cmd_response_get_node(data); + default: return; } } -- cgit v1.2.3 From a2fe55b5c31e08ca4df165172269e7eb58d75bf6 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Fri, 6 Jan 2023 13:54:15 +0100 Subject: add node to gui on get node response --- confui/main.cpp | 6 ++++-- confui/mainwindow.h | 3 +++ confui/mesh_connector.cpp | 9 ++++++++- confui/mesh_connector.h | 3 +++ confui/serial.cpp | 22 +++++++++++++++++----- 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/confui/main.cpp b/confui/main.cpp index a860f28..ae52a61 100644 --- a/confui/main.cpp +++ b/confui/main.cpp @@ -7,10 +7,12 @@ 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[]) { g_cd_endianness = *_ptest; g_cd_app = new QApplication(argc, argv); - CDMainWindow w; - w.show(); + g_cd_main_window = new CDMainWindow(); + g_cd_main_window->show(); return g_cd_app->exec(); } diff --git a/confui/mainwindow.h b/confui/mainwindow.h index 587c447..4093cd1 100644 --- a/confui/mainwindow.h +++ b/confui/mainwindow.h @@ -10,6 +10,9 @@ class CDAutomationsTabWidget; class CDNodeOverviewTabWidget; +class CDMainWindow; + +extern CDMainWindow *g_cd_main_window; /** * @brief main window diff --git a/confui/mesh_connector.cpp b/confui/mesh_connector.cpp index b7991b7..fb6ac1d 100644 --- a/confui/mesh_connector.cpp +++ b/confui/mesh_connector.cpp @@ -41,6 +41,7 @@ CDMeshConnector::CDMeshConnector() { 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(); @@ -187,7 +188,7 @@ string CDMeshConnector::cd_mac_to_string(cd_mac_addr_t mac) { 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[15], uuid[14], uuid[13], uuid[12], uuid[11], uuid[10], uuid[9], uuid[8], uuid[7], uuid[6], uuid[5], uuid[4], uuid[3], uuid[2], uuid[1], uuid[0]); + 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; @@ -196,3 +197,9 @@ string CDMeshConnector::cd_uuid_to_string(cd_uuid_t uuid) { 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 node : _nodes) + if (memcmp(node.second->uuid, uuid, sizeof(cd_uuid_t)) == 0) return node.first; + return create_node({}); +} diff --git a/confui/mesh_connector.h b/confui/mesh_connector.h index 43f78d5..1c9f938 100644 --- a/confui/mesh_connector.h +++ b/confui/mesh_connector.h @@ -29,6 +29,7 @@ enum cd_e_automation_type { 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 */ bool light_on; /** @brief state of light on node */ @@ -102,6 +103,7 @@ 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); // network modification functions /** @brief create empty automation */ @@ -159,6 +161,7 @@ public: 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 index c972ffb..bfb809e 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -2,6 +2,8 @@ #include "../shared/serial_parse.h" #include "../shared/bin.h" #include "../shared/pclient.h" +#include "mainwindow.h" +#include "mesh_connector.h" #include #include @@ -122,11 +124,21 @@ void cd_cmd_ping(cd_s_bin* data) { 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"); - // WIP - // cd_gui_node_id_t id = get_or_create_id(node->uuid); - // node* gui_node = g_cd_mesh_connector->get_node(id); - // (fill gui_node) - // (refresh gui) + + 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); + + 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((char*) gui_node->name); // TODO: set name to non-const pointer + 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; + + g_cd_main_window->update(); } void cd_cmd_response_get_node(cd_s_bin* data) { -- cgit v1.2.3 From 75eecca201016aae2dde136f222c2694822f2d12 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Fri, 6 Jan 2023 13:55:18 +0100 Subject: gui node name to non-const pointer --- confui/mesh_connector.h | 2 +- confui/serial.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/confui/mesh_connector.h b/confui/mesh_connector.h index 1c9f938..ccab6bd 100644 --- a/confui/mesh_connector.h +++ b/confui/mesh_connector.h @@ -31,7 +31,7 @@ typedef struct { 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; diff --git a/confui/serial.cpp b/confui/serial.cpp index bfb809e..c7a52e5 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -131,7 +131,7 @@ void cd_cmd_response_get_node_parse_node(cd_s_cmd_node* 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((char*) gui_node->name); // TODO: set name to non-const pointer + 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; -- cgit v1.2.3 From 62fedb0f2992222e340b62dea7f976c9bff3063e Mon Sep 17 00:00:00 2001 From: lonkaars Date: Fri, 6 Jan 2023 14:28:55 +0100 Subject: create links in gui --- confui/mesh_connector.cpp | 8 ++++++++ confui/mesh_connector.h | 1 + confui/serial.cpp | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/confui/mesh_connector.cpp b/confui/mesh_connector.cpp index fb6ac1d..2630da6 100644 --- a/confui/mesh_connector.cpp +++ b/confui/mesh_connector.cpp @@ -203,3 +203,11 @@ cd_uid_t CDMeshConnector::get_or_create_node_by_uuid(cd_uuid_t uuid) { 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 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 ccab6bd..64ab471 100644 --- a/confui/mesh_connector.h +++ b/confui/mesh_connector.h @@ -104,6 +104,7 @@ public: /** @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 */ diff --git a/confui/serial.cpp b/confui/serial.cpp index c7a52e5..bdd16ab 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -125,9 +125,11 @@ 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; @@ -138,6 +140,24 @@ void cd_cmd_response_get_node_parse_node(cd_s_cmd_node* node) { 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(); } -- cgit v1.2.3 From b155a5fa4b97f6f5f63f7079c671b5965db9d022 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Fri, 6 Jan 2023 15:29:26 +0100 Subject: send POST_LINK --- confui/mesh_connector.cpp | 26 ++++++++++++++++++++------ confui/mesh_connector.h | 21 +++++++++++---------- confui/ui_automation.cpp | 4 ++-- confui/ui_node.cpp | 2 +- shared/pclient.c | 9 +++++---- shared/protocol.h | 8 ++++---- 6 files changed, 43 insertions(+), 27 deletions(-) diff --git a/confui/mesh_connector.cpp b/confui/mesh_connector.cpp index 2630da6..c77c159 100644 --- a/confui/mesh_connector.cpp +++ b/confui/mesh_connector.cpp @@ -4,6 +4,7 @@ #include #include +#include "../shared/pclient.h" #include "mesh_connector.h" using std::pair; @@ -99,7 +100,7 @@ map 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, @@ -111,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)); @@ -147,11 +155,17 @@ 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 + + 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) { @@ -161,7 +175,7 @@ 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; } diff --git a/confui/mesh_connector.h b/confui/mesh_connector.h index 64ab471..8c1fc91 100644 --- a/confui/mesh_connector.h +++ b/confui/mesh_connector.h @@ -18,12 +18,10 @@ typedef uint32_t cd_uid_t; /** @brief link/automation id type */ typedef uint32_t cd_link_t; -/** @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 { @@ -117,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. * @@ -126,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. @@ -142,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 * 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..56ff004 100644 --- a/confui/ui_node.cpp +++ b/confui/ui_node.cpp @@ -54,7 +54,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(); } diff --git a/shared/pclient.c b/shared/pclient.c index 728bfa0..ff2315c 100644 --- a/shared/pclient.c +++ b/shared/pclient.c @@ -45,8 +45,8 @@ cd_s_bin* cd_cmd_gen_post_link_add(cd_uuid_t button, cd_uuid_t light, cd_e_cmd_l msg->opcode = CD_CMD_POST_LINK; msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); msg->add = true; - memcpy(&msg->button, &button, sizeof(cd_uuid_t)); - memcpy(&msg->led, &light, sizeof(cd_uuid_t)); + memcpy(msg->button, button, sizeof(cd_uuid_t)); + memcpy(msg->led, light, sizeof(cd_uuid_t)); msg->type = type; return bin; @@ -58,8 +58,9 @@ cd_s_bin* cd_cmd_gen_post_link_rm(cd_uuid_t button, cd_uuid_t light) { msg->opcode = CD_CMD_POST_LINK; msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); msg->add = false; - memcpy(&msg->button, &button, sizeof(cd_uuid_t)); - memcpy(&msg->led, &light, sizeof(cd_uuid_t)); + memcpy(msg->button, button, sizeof(cd_uuid_t)); + memcpy(msg->led, light, sizeof(cd_uuid_t)); + msg->type = 0; return bin; } diff --git a/shared/protocol.h b/shared/protocol.h index cad9a1c..b9a2c93 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -60,9 +60,9 @@ typedef struct { } cd_s_cmd_post_led; typedef enum { - CD_CMD_LINK_TYPE_TOGGLE = 0x00, - CD_CMD_LINK_TYPE_TURN_ON = 0x01, - CD_CMD_LINK_TYPE_TURN_OFF = 0x02, + CD_CMD_LINK_TYPE_TOGGLE = 0x00, /** @brief button toggles light */ + CD_CMD_LINK_TYPE_TURN_ON = 0x01, /** @brief button always turns on light (regardless of previous state) */ + CD_CMD_LINK_TYPE_TURN_OFF = 0x02, /** @brief button always turns off light (regardless of previous state) */ } cd_e_cmd_link_type; typedef struct { @@ -71,7 +71,7 @@ typedef struct { cd_uuid_t button; /** @brief uuid of button node */ cd_uuid_t led; /** @brief uuid of led node */ cd_cmd_bool_t add; /** @brief `true` to create/overwrite link, `false` to remove link */ - cd_e_cmd_link_type type; /** @brief link type */ + uint8_t type; /** @brief link type cd_e_cmd_link_type */ } cd_s_cmd_post_link; typedef struct { -- cgit v1.2.3 From b25530da670709e7d54afd70fe33e1dd6368d45e Mon Sep 17 00:00:00 2001 From: lonkaars Date: Fri, 6 Jan 2023 15:31:13 +0100 Subject: add implementation status to protocol.h --- shared/protocol.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/protocol.h b/shared/protocol.h index b9a2c93..3ec9838 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -170,12 +170,12 @@ static size_t (* const CD_CMD_HANDLERS_SIZEOF[CD_CMD_COUNT])(cd_s_bin*) = { /** @brief stores message handlers in array with opcode as index */ static cd_cmd_handler_t* const CD_CMD_HANDLERS[CD_CMD_COUNT] = { - [CD_CMD_PING] = &cd_cmd_ping, + [CD_CMD_PING] = &cd_cmd_ping, // implemented [CD_CMD_GET_NODE] = &cd_cmd_get_node, [CD_CMD_POST_LED] = &cd_cmd_post_led, - [CD_CMD_POST_LINK] = &cd_cmd_post_link, + [CD_CMD_POST_LINK] = &cd_cmd_post_link, // implemented [CD_CMD_POST_NET] = &cd_cmd_post_net, - [CD_CMD_RESPONSE] = &cd_cmd_response, + [CD_CMD_RESPONSE] = &cd_cmd_response, // WIP }; #ifdef __cplusplus -- cgit v1.2.3 From 847b4a5d588ec504865398c21c3bcb73a6fc1fab Mon Sep 17 00:00:00 2001 From: lonkaars Date: Sat, 7 Jan 2023 13:47:41 +0100 Subject: implement get node --- confui/mainwindow.cpp | 5 +++++ confui/ui_node.cpp | 5 +++++ shared/pclient.c | 13 +++++++------ shared/protocol.h | 2 +- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/confui/mainwindow.cpp b/confui/mainwindow.cpp index b5bbdf0..4c9b857 100644 --- a/confui/mainwindow.cpp +++ b/confui/mainwindow.cpp @@ -7,6 +7,7 @@ #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; @@ -73,6 +74,10 @@ void CDMainWindow::update() { 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(); } diff --git a/confui/ui_node.cpp b/confui/ui_node.cpp index 56ff004..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() { diff --git a/shared/pclient.c b/shared/pclient.c index ff2315c..1b8e4e5 100644 --- a/shared/pclient.c +++ b/shared/pclient.c @@ -23,7 +23,8 @@ cd_s_bin* cd_cmd_gen_get_node(bool all, cd_uuid_t uuid) { msg->opcode = CD_CMD_GET_NODE; msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); msg->all = all; - memcpy(&msg->uuid, &uuid, sizeof(cd_uuid_t)); + if (uuid != NULL) memcpy(msg->uuid, uuid, sizeof(cd_uuid_t)); + else memset(msg->uuid, 0, sizeof(cd_uuid_t)); return bin; } @@ -34,7 +35,7 @@ cd_s_bin* cd_cmd_gen_post_led(bool on, cd_uuid_t uuid) { msg->opcode = CD_CMD_POST_LED; msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); msg->on = on; - memcpy(&msg->uuid, &uuid, sizeof(cd_uuid_t)); + memcpy(msg->uuid, uuid, sizeof(cd_uuid_t)); return bin; } @@ -71,7 +72,7 @@ cd_s_bin* cd_cmd_gen_post_net_add(cd_uuid_t uuid) { msg->opcode = CD_CMD_POST_NET; msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); msg->join = true; - memcpy(&msg->uuid, &uuid, sizeof(cd_uuid_t)); + memcpy(msg->uuid, uuid, sizeof(cd_uuid_t)); return bin; } @@ -82,7 +83,7 @@ cd_s_bin* cd_cmd_gen_post_net_rm(cd_uuid_t uuid) { msg->opcode = CD_CMD_POST_NET; msg->id = cd_bin_hton16(cd_protocol_fresh_message_id()); msg->join = false; - memcpy(&msg->uuid, &uuid, sizeof(cd_uuid_t)); + memcpy(msg->uuid, uuid, sizeof(cd_uuid_t)); return bin; } @@ -120,8 +121,8 @@ cd_s_cmd_node* cd_cmd_node_alloc(const char* name, cd_s_cmd_node base, uint16_t size_t remaining_size = sizeof(char) * name_len + links_size; cd_s_cmd_node* node = malloc(sizeof(cd_s_cmd_node) + remaining_size); - memcpy(&node->uuid, &base.uuid, sizeof(cd_uuid_t)); - memcpy(&node->address, &base.address, sizeof(cd_mac_addr_t)); + memcpy(node->uuid, base.uuid, sizeof(cd_uuid_t)); + memcpy(node->address, base.address, sizeof(cd_mac_addr_t)); node->name_len = name_len; node->light_on = base.light_on; node->provisioned = base.provisioned; diff --git a/shared/protocol.h b/shared/protocol.h index 3ec9838..c742c82 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -171,7 +171,7 @@ static size_t (* const CD_CMD_HANDLERS_SIZEOF[CD_CMD_COUNT])(cd_s_bin*) = { /** @brief stores message handlers in array with opcode as index */ static cd_cmd_handler_t* const CD_CMD_HANDLERS[CD_CMD_COUNT] = { [CD_CMD_PING] = &cd_cmd_ping, // implemented - [CD_CMD_GET_NODE] = &cd_cmd_get_node, + [CD_CMD_GET_NODE] = &cd_cmd_get_node, // implemented [CD_CMD_POST_LED] = &cd_cmd_post_led, [CD_CMD_POST_LINK] = &cd_cmd_post_link, // implemented [CD_CMD_POST_NET] = &cd_cmd_post_net, -- cgit v1.2.3 From d5288693e86db33ab6743c902440825e5eec1314 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Sat, 7 Jan 2023 13:55:00 +0100 Subject: mesh network message publishing commands all fully implemented --- confui/mesh_connector.cpp | 29 +++++++++++++++++++++-------- shared/protocol.h | 8 ++++---- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/confui/mesh_connector.cpp b/confui/mesh_connector.cpp index c77c159..7ef0f02 100644 --- a/confui/mesh_connector.cpp +++ b/confui/mesh_connector.cpp @@ -160,9 +160,11 @@ void CDMeshConnector::remove_link(cd_link_t link_handle, bool publish) { if (_links.count(link_handle) == 0) return; // invalid handle if (_links[link_handle] == nullptr) return; // already removed link - 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); + 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; @@ -177,19 +179,30 @@ void CDMeshConnector::remove_node(cd_uid_t node_handle) { 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) { diff --git a/shared/protocol.h b/shared/protocol.h index c742c82..b9a2c93 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -170,12 +170,12 @@ static size_t (* const CD_CMD_HANDLERS_SIZEOF[CD_CMD_COUNT])(cd_s_bin*) = { /** @brief stores message handlers in array with opcode as index */ static cd_cmd_handler_t* const CD_CMD_HANDLERS[CD_CMD_COUNT] = { - [CD_CMD_PING] = &cd_cmd_ping, // implemented - [CD_CMD_GET_NODE] = &cd_cmd_get_node, // implemented + [CD_CMD_PING] = &cd_cmd_ping, + [CD_CMD_GET_NODE] = &cd_cmd_get_node, [CD_CMD_POST_LED] = &cd_cmd_post_led, - [CD_CMD_POST_LINK] = &cd_cmd_post_link, // implemented + [CD_CMD_POST_LINK] = &cd_cmd_post_link, [CD_CMD_POST_NET] = &cd_cmd_post_net, - [CD_CMD_RESPONSE] = &cd_cmd_response, // WIP + [CD_CMD_RESPONSE] = &cd_cmd_response, }; #ifdef __cplusplus -- cgit v1.2.3 From 3fbe1e106abd0d89cd6aa953eefa4d6adf956f88 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Sat, 7 Jan 2023 13:56:10 +0100 Subject: add todo comments for WIP --- confui/serial.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/confui/serial.cpp b/confui/serial.cpp index bdd16ab..6a58fc2 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -195,6 +195,9 @@ void cd_cmd_response(cd_s_bin* data) { 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; // TODO + case CD_CMD_POST_LINK: return; // TODO + case CD_CMD_POST_NET: return; // TODO default: return; } } -- cgit v1.2.3 From 7c9afe1982c1c3778e65740fa2e161621d380285 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Sat, 7 Jan 2023 14:37:37 +0100 Subject: remove test code from serial.cpp --- confui/serial.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/confui/serial.cpp b/confui/serial.cpp index 6a58fc2..7a9e102 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -97,28 +97,6 @@ void cd_cmd_ping(cd_s_bin* data) { cd_s_bin* response = cd_cmd_res_status((cd_e_scmds) cast->opcode, cast->id, false); cd_pclient_send(response); free(response); - response = nullptr; - - // cd_uuid_t test_node_light_addrs[] = { - // { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }, - // }; - // cd_s_cmd_node* test_node = cd_cmd_node_alloc("gert", { - // .uuid = { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }, - // .address = { 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, }, - // .light_on = false, - // .provisioned = false, - // .button_pub = 0xdeadbeef, - // }, 1, test_node_light_addrs); - - // cd_s_cmd_node* nodes[] = { test_node }; - // cd_s_cmd_response_get_node* response_get_nodes = cd_cmd_get_node_res_from_node_arr(1, nodes); - // free(test_node); - - // cd_s_bin* response = cd_cmd_res(CD_CMD_GET_NODE, 0xf88f, cd_cmd_response_get_node_sizeof(response_get_nodes), (uint8_t*) response_get_nodes); - // free(response_get_nodes); - - // cd_pclient_send(response); - // free(response); } void cd_cmd_response_get_node_parse_node(cd_s_cmd_node* node) { -- cgit v1.2.3 From b083c8e08d610a4e74f39f66f3daa191301893b1 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Sat, 7 Jan 2023 14:42:37 +0100 Subject: implement response handlers for other post commands --- confui/serial.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/confui/serial.cpp b/confui/serial.cpp index 7a9e102..b3f1cd6 100644 --- a/confui/serial.cpp +++ b/confui/serial.cpp @@ -164,6 +164,21 @@ void cd_cmd_response_ping(cd_s_bin* data) { 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); @@ -173,9 +188,9 @@ void cd_cmd_response(cd_s_bin* data) { 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; // TODO - case CD_CMD_POST_LINK: return; // TODO - case CD_CMD_POST_NET: return; // TODO + 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; } } -- cgit v1.2.3