Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expander improvements I #74

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
10 changes: 8 additions & 2 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ void process_tree(owl_tree *const tree, bool from_expander) {
if (expander_module->type != expander) {
throw std::runtime_error("module \"" + expander_name + "\" is not an expander");
}
while (!expander_module->get_property("is_ready")->boolean_value) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
const Expander_ptr expander = std::static_pointer_cast<Expander>(expander_module);
const std::vector<ConstExpression_ptr> arguments = compile_arguments(constructor.argument);
const Module_ptr proxy = std::make_shared<Proxy>(module_name, expander_name, module_type, expander, arguments);
Expand Down Expand Up @@ -383,6 +386,9 @@ void run_step(Module_ptr module) {
}

void app_main() {
// delay so log can get send out completely
vTaskDelay(2000 / portTICK_PERIOD_MS);

const uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
Expand All @@ -398,8 +404,6 @@ void app_main() {
uart_enable_pattern_det_baud_intr(UART_NUM_0, '\n', 1, 9, 0, 0);
uart_pattern_queue_reset(UART_NUM_0, 100);

printf("\nReady.\n");

try {
Global::add_module("core", core_module = std::make_shared<Core>("core"));
} catch (const std::runtime_error &e) {
Expand All @@ -420,6 +424,8 @@ void app_main() {
echo("error while verifying OTA: %s", e.what());
}

printf("\nReady.\n");

while (true) {
try {
process_uart();
Expand Down
86 changes: 70 additions & 16 deletions main/modules/expander.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,20 @@ Expander::Expander(const std::string name,
const ConstSerial_ptr serial,
const gpio_num_t boot_pin,
const gpio_num_t enable_pin,
const u_int16_t boot_wait_time,
MessageHandler message_handler)
: Module(expander, name), serial(serial), boot_pin(boot_pin), enable_pin(enable_pin), message_handler(message_handler) {
: Module(expander, name),
serial(serial),
boot_pin(boot_pin),
enable_pin(enable_pin),
boot_wait_time(boot_wait_time),
message_handler(message_handler) {

boot_state = BOOT_INIT;
boot_start_time = 0;

this->properties["last_message_age"] = std::make_shared<IntegerVariable>();
this->properties["is_ready"] = std::make_shared<BooleanVariable>(false);

serial->enable_line_detection();
if (boot_pin != GPIO_NUM_NC && enable_pin != GPIO_NUM_NC) {
Expand All @@ -25,32 +36,23 @@ Expander::Expander(const std::string name,
gpio_set_level(enable_pin, 0);
delay(100);
gpio_set_level(enable_pin, 1);
} else {
serial->write_checked_line("core.restart()", 14);
}

char buffer[1024] = "";
int len = 0;
const unsigned long int start = millis();
do {
if (millis_since(start) > 1000) {
echo("warning: expander is not booting");
break;
}
if (serial->available()) {
len = serial->read_line(buffer);
strip(buffer, len);
echo("%s: %s", name.c_str(), buffer);
}
} while (strcmp("Ready.", buffer));
boot_start_time = millis();
}

void Expander::step() {
handle_boot_process();

static char buffer[1024];
while (this->serial->has_buffered_lines()) {
int len = this->serial->read_line(buffer);
check(buffer, len);
this->last_message_millis = millis();
if (buffer[0] == '!' && buffer[1] == '!') {
this->message_handler(&buffer[2], false, true); // Don't trigger core keep-alive from expander broadcasts
this->message_handler(&buffer[2], false, true);
} else {
echo("%s: %s", this->name.c_str(), buffer);
}
Expand All @@ -59,6 +61,58 @@ void Expander::step() {
Module::step();
}

void Expander::handle_boot_process() {
echo("boot state: %d", boot_state);
switch (boot_state) {
case BOOT_INIT:
boot_start_time = millis();
boot_state = BOOT_WAITING;
break;

case BOOT_WAITING: {
char buffer[1024];
if (this->serial->available()) {
int len = this->serial->read_line(buffer);
strip(buffer, len);
echo("%s: %s", this->name.c_str(), buffer);

if (strcmp("Ready.", buffer) == 0) {
this->properties.at("is_ready")->boolean_value = true;
echo("%s: Booting process completed successfully", this->name.c_str());
boot_state = BOOT_READY;
return;
}
}

if (boot_wait_time == 0 && millis_since(boot_start_time) >= 30000) {
echo("Warning: expander %s did not send 'Ready.', trying restart", this->name.c_str());
boot_state = BOOT_RESTARTING;
} else if (boot_wait_time != 0 && millis_since(boot_start_time) > boot_wait_time) {
echo("Error: expander %s did not boot in the expected time (%d ms)", this->name.c_str(), boot_wait_time);
boot_state = BOOT_FAILED;
}
break;
}

case BOOT_RESTARTING:
if (boot_pin != GPIO_NUM_NC && enable_pin != GPIO_NUM_NC) {
gpio_set_level(enable_pin, 0);
delay(100);
gpio_set_level(enable_pin, 1);
} else {
serial->write_checked_line("core.restart()", 14);
}
boot_start_time = millis();
boot_state = BOOT_WAITING;
break;

case BOOT_READY:
case BOOT_FAILED:
// Do nothing, boot process is complete
break;
}
}

void Expander::call(const std::string method_name, const std::vector<ConstExpression_ptr> arguments) {
if (method_name == "run") {
Module::expect(arguments, 1, string);
Expand Down
14 changes: 14 additions & 0 deletions main/modules/expander.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,30 @@ class Expander : public Module {
private:
unsigned long int last_message_millis = 0;

enum BootState {
BOOT_INIT,
BOOT_WAITING,
BOOT_RESTARTING,
BOOT_READY,
BOOT_FAILED
};
BootState boot_state;
unsigned long boot_start_time;

void handle_boot_process();

public:
const ConstSerial_ptr serial;
const gpio_num_t boot_pin;
const gpio_num_t enable_pin;
const u_int16_t boot_wait_time;
MessageHandler message_handler;

Expander(const std::string name,
const ConstSerial_ptr serial,
const gpio_num_t boot_pin,
const gpio_num_t enable_pin,
const u_int16_t boot_wait_time,
MessageHandler message_handler);
void step() override;
void call(const std::string method_name, const std::vector<ConstExpression_ptr> arguments) override;
Expand Down
29 changes: 24 additions & 5 deletions main/modules/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,38 @@ Module_ptr Module::create(const std::string type,
if (type == "Core") {
throw std::runtime_error("creating another core module is forbidden");
} else if (type == "Expander") {
if (arguments.size() != 1 && arguments.size() != 3) {
if (arguments.size() < 1 || arguments.size() > 4) {
throw std::runtime_error("unexpected number of arguments");
}
Module::expect(arguments, -1, identifier, integer, integer);
Module::expect(arguments, -1, identifier, integer, integer, integer);
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 = std::static_pointer_cast<const Serial>(module);
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);

gpio_num_t boot_pin = GPIO_NUM_NC;
gpio_num_t enable_pin = GPIO_NUM_NC;
u_int16_t boot_wait_time = 0; // infinite

switch (arguments.size()) {
case 1:
break;
case 2:
boot_wait_time = arguments[1]->evaluate_integer();
break;
case 3:
boot_pin = (gpio_num_t)arguments[1]->evaluate_integer();
enable_pin = (gpio_num_t)arguments[2]->evaluate_integer();
break;
case 4:
boot_pin = (gpio_num_t)arguments[1]->evaluate_integer();
enable_pin = (gpio_num_t)arguments[2]->evaluate_integer();
boot_wait_time = arguments[3]->evaluate_integer();
break;
}
return std::make_shared<Expander>(name, serial, boot_pin, enable_pin, boot_wait_time, message_handler);
} else if (type == "Bluetooth") {
Module::expect(arguments, 1, string);
std::string device_name = arguments[0]->evaluate_string();
Expand Down
3 changes: 3 additions & 0 deletions main/modules/proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Proxy::Proxy(const std::string name,
const Expander_ptr expander,
const std::vector<ConstExpression_ptr> arguments)
: Module(proxy, name), expander(expander) {
this->properties["received_message"] = std::make_shared<BooleanVariable>(false);

static char buffer[256];
int pos = std::sprintf(buffer, "%s = %s(", name.c_str(), module_type.c_str());
pos += write_arguments_to_buffer(arguments, &buffer[pos]);
Expand All @@ -28,6 +30,7 @@ void Proxy::call(const std::string method_name, const std::vector<ConstExpressio
void Proxy::write_property(const std::string property_name, const ConstExpression_ptr expression, const bool from_expander) {
if (!this->properties.count(property_name)) {
this->properties[property_name] = std::make_shared<Variable>(expression->type);
this->properties.at("received_message")->boolean_value = true;
}
if (!from_expander) {
static char buffer[256];
Expand Down