Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/module_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,29 @@ When a fifth connects, the oldest entry is removed.

To force re-pairing, call `bluetooth.reset_bonds()` to clear stored bonds, then restart the ESP to apply the change.

## Serial Bus

The serial bus module lets multiple ESP32s share a UART link with a coordinator that polls peers in turn.

| Constructor | Description | Arguments |
| ----------------------------- | ---------------------------------------------- | --------------- |
| `bus = SerialBus(serial, id)` | Attach to a serial module with local node `id` | `Serial`, `int` |

| Properties | Description | Data type |
| ---------------------- | -------------------------------------------------- | --------- |
| `bus.is_coordinator` | Whether this node is acting as bus coordinator | `bool` |
| `bus.peer_count` | Number of peer nodes the coordinator will poll | `int` |
| `bus.last_message_age` | Milliseconds since the last bus frame was received | `int` |

| Methods | Description | Arguments |
| ---------------------------------- | ---------------------------------------------------------------------------------------------- | ------------ |
| `bus.send(receiver, payload)` | Send a payload to a peer `receiver` (0-255); payload must not contain newlines | `int`, `str` |
| `bus.configure(receiver, script)` | Send a multi-line setup script to a peer and restart it (`!-`/`!+` framing is handled for you) | `int`, `str` |
| `bus.set_coordinator(peer_ids...)` | Mark this node as coordinator and set the list of peer IDs to poll in round-robin order | `int`... |

Use `bus.configure()` to push startup scripts line by line;
it wraps the required framing and finishes with a restart so peers boot with the new configuration.

## Input

The input module is associated with a digital input pin that is be connected to a pushbutton, sensor or other input signal.
Expand Down
13 changes: 11 additions & 2 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ std::vector<ConstExpression_ptr> compile_arguments(const struct owl_ref ref) {
return arguments;
}

Module_ptr get_or_create_property_module(const std::string &module_name) {
if (Global::has_module(module_name)) {
return Global::get_module(module_name);
}
const Module_ptr module = Module::create_placeholder(module_name);
Global::add_module(module_name, module);
return module;
}

Expression_ptr compile_expression(const struct owl_ref ref) {
const struct parsed_expression expression = parsed_expression_get(ref);
switch (expression.type) {
Expand Down Expand Up @@ -149,7 +158,7 @@ std::vector<Action_ptr> compile_actions(const struct owl_ref ref) {
} else if (!action.property_assignment.empty) {
const struct parsed_property_assignment property_assignment = parsed_property_assignment_get(action.property_assignment);
const std::string module_name = identifier_to_string(property_assignment.module_name);
const Module_ptr module = Global::get_module(module_name);
const Module_ptr module = get_or_create_property_module(module_name);
const std::string property_name = identifier_to_string(property_assignment.property_name);
const ConstExpression_ptr expression = compile_expression(property_assignment.expression);
actions.push_back(std::make_shared<PropertyAssignment>(module, property_name, expression));
Expand Down Expand Up @@ -233,7 +242,7 @@ void process_tree(owl_tree *const tree, bool from_expander) {
} else if (!statement.property_assignment.empty) {
const struct parsed_property_assignment property_assignment = parsed_property_assignment_get(statement.property_assignment);
const std::string module_name = identifier_to_string(property_assignment.module_name);
const Module_ptr module = Global::get_module(module_name);
const Module_ptr module = get_or_create_property_module(module_name);
const std::string property_name = identifier_to_string(property_assignment.property_name);
const ConstExpression_ptr expression = compile_expression(property_assignment.expression);
module->write_property(property_name, expression, from_expander);
Expand Down
4 changes: 4 additions & 0 deletions main/modules/core.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "core.h"
#include "../global.h"
#include "../storage.h"
#include "../utils/debug.h"
#include "../utils/ota.h"
#include "../utils/string_utils.h"
#include "../utils/timing.h"
Expand Down Expand Up @@ -131,6 +132,9 @@ void Core::call(const std::string method_name, const std::vector<ConstExpression
throw std::runtime_error("failed to set pin");
}
echo("GPIO_set[%d] set to %d", gpio_num, value);
} else if (method_name == "debug") {
Module::expect(arguments, 0);
debug::print_memory_usage();
} else if (method_name == "get_pin_strapping") {
Module::expect(arguments, 1, integer);
const gpio_num_t gpio_num = static_cast<gpio_num_t>(arguments[0]->evaluate_integer());
Expand Down
34 changes: 34 additions & 0 deletions main/modules/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "roboclaw_motor.h"
#include "roboclaw_wheels.h"
#include "serial.h"
#include "serial_bus.h"
#include "stepper_motor.h"
#include "temperature_sensor.h"
#include <stdarg.h>
Expand All @@ -42,6 +43,21 @@
#define DEFAULT_SCL_PIN GPIO_NUM_22
#endif

namespace {
class PlaceholderModule : public Module {
public:
explicit PlaceholderModule(const std::string &name) : Module(dynamic_module, name) {
}

void write_property(const std::string property_name, const ConstExpression_ptr expression, const bool from_expander) override {
if (!this->properties.count(property_name)) {
this->properties[property_name] = std::make_shared<Variable>(expression->type);
}
Module::write_property(property_name, expression, from_expander);
}
};
} // namespace

Module::Module(const ModuleType type, const std::string name) : type(type), name(name) {
}

Expand Down Expand Up @@ -91,6 +107,20 @@ Module_ptr Module::create(const std::string type,
const gpio_num_t boot_pin = arguments.size() > 1 ? (gpio_num_t)arguments[1]->evaluate_integer() : GPIO_NUM_NC;
const gpio_num_t enable_pin = arguments.size() > 2 ? (gpio_num_t)arguments[2]->evaluate_integer() : GPIO_NUM_NC;
return std::make_shared<Expander>(name, serial, boot_pin, enable_pin, message_handler);
} else if (type == "SerialBus") {
Module::expect(arguments, 2, identifier, integer);
const std::string serial_name = arguments[0]->evaluate_identifier();
Module_ptr module = Global::get_module(serial_name);
if (module->type != serial) {
throw std::runtime_error("module \"" + serial_name + "\" is no serial connection");
}
const ConstSerial_ptr serial_module = std::static_pointer_cast<const Serial>(module);
const long node_id_value = arguments[1]->evaluate_integer();
if (node_id_value < 0 || node_id_value > 255) {
throw std::runtime_error("serial bus id must be between 0 and 255");
}
const uint8_t node_id = static_cast<uint8_t>(node_id_value);
return std::make_shared<SerialBus>(name, serial_module, node_id, message_handler);
} else if (type == "Bluetooth") {
Module::expect(arguments, 1, string);
std::string device_name = arguments[0]->evaluate_string();
Expand Down Expand Up @@ -371,6 +401,10 @@ Module_ptr Module::create(const std::string type,
}
}

Module_ptr Module::create_placeholder(const std::string &name) {
return std::make_shared<PlaceholderModule>(name);
}

void Module::step() {
if (this->output_on) {
const std::string output = this->get_output();
Expand Down
3 changes: 3 additions & 0 deletions main/modules/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ enum ModuleType {
analog_unit,
temperature_sensor,
proxy,
serial_bus,
dynamic_module,
};

class Module;
Expand Down Expand Up @@ -85,4 +87,5 @@ class Module {
Variable_ptr get_property(const std::string property_name) const;
virtual void write_property(const std::string property_name, const ConstExpression_ptr expression, const bool from_expander = false);
virtual void handle_can_msg(const uint32_t id, const int count, const uint8_t *const data);
static Module_ptr create_placeholder(const std::string &name);
};
Loading