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

External Expander #64

Draft
wants to merge 24 commits into
base: main
Choose a base branch
from
Draft
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
22 changes: 18 additions & 4 deletions gen_parser.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/bin/bash

OS_TYPE=$(uname)

echo "Generating parser..."
if [[ "language.owl" -nt main/parser.h ]]
then
Expand All @@ -15,11 +17,23 @@ then
exit 1
fi

# remove minimum size of 4096 bytes (see https://github.com/zauberzeug/lizard/issues/23)
sed -i '' 's/while (n < size \|\| n < 4096)/while (n < size)/g' main/parser.h
echo "Detected OS: $OS_TYPE"

# Apply the appropriate sed syntax based on the operating system
if [[ "$OS_TYPE" == "Darwin" ]]; then
# macOS
# remove minimum size of 4096 bytes (see https://github.com/zauberzeug/lizard/issues/23)
sed -i '' 's/while (n < size \|\| n < 4096)/while (n < size)/g' main/parser.h

# increase RESERVATION_AMOUNT to 11 (see https://github.com/zauberzeug/field_friend/issues/7)
sed -i '' 's/#define RESERVATION_AMOUNT 10/#define RESERVATION_AMOUNT 11/g' main/parser.h
# increase RESERVATION_AMOUNT to 11 (see https://github.com/zauberzeug/field_friend/issues/7)
sed -i '' 's/#define RESERVATION_AMOUNT 10/#define RESERVATION_AMOUNT 11/g' main/parser.h
else
# Linux (Ubuntu or others)
# sed did unwanted to the file, so we use perl instead
perl -pi -e 's/while \(n < size \|\| n < 4096\)/while (n < size)/g' main/parser.h

perl -pi -e 's/#define RESERVATION_AMOUNT 10/#define RESERVATION_AMOUNT 11/g' main/parser.h
fi
else
echo "Nothing to do."
fi
73 changes: 66 additions & 7 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
#include <vector>

#define BUFFER_SIZE 1024
#define XON 0x11
#define XOFF 0x13
#define FILTER_MODE 0x80
#define ID_TAG 0x81

Core_ptr core_module;

Expand Down Expand Up @@ -206,13 +210,19 @@ void process_tree(owl_tree *const tree, bool from_expander) {
const std::string module_type = identifier_to_string(constructor.module_type);
const std::string expander_name = identifier_to_string(constructor.expander_name);
const Module_ptr expander_module = Global::get_module(expander_name);
if (expander_module->type != expander) {
if (expander_module->type == expander) {
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);
Global::add_module(module_name, proxy);
} else if (expander_module->type == external_expander) {
const ExternalExpander_ptr external_expander = std::static_pointer_cast<ExternalExpander>(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, external_expander, arguments);
Global::add_module(module_name, proxy);
} else {
throw std::runtime_error("module \"" + expander_name + "\" is not an expander");
}
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);
Global::add_module(module_name, proxy);
}
} else if (!statement.method_call.empty) {
const struct parsed_method_call method_call = parsed_method_call_get(statement.method_call);
Expand Down Expand Up @@ -359,7 +369,7 @@ void process_line(const char *line, const int len) {
process_lizard(line);
}
}

bool adress_mode = false;
void process_uart() {
static char input[BUFFER_SIZE];
while (true) {
Expand All @@ -368,8 +378,52 @@ void process_uart() {
break;
}
int len = uart_read_bytes(UART_NUM_0, (uint8_t *)input, pos + 1, 0);

if (adress_mode && !(input[0] == ID_TAG)) {
// Keep this debug for multidevice testing
echo("Debug: 0 Character"); // Debug
echo("Debug: Adress is: %d", input[0]);
echo("Debug: it should be: %d", ID_TAG);
break;
}

len = check(input, len);
process_line(input, len);
for (int i = 0; i < len; ++i) {
if (input[i] == XOFF) {
uart_xon = false;
return;
} else if (input[i] == XON) {
uart_xon = true;
return;
} else if (input[i] == FILTER_MODE) {
if (Storage::get_device_id() == 0x00) {
echo("Debug: FILTER_MODE received and device id is not set. Will not switch to filter mode");
return;
}
adress_mode = true;
uart_xon = false;
return;
}
}

if (adress_mode) {
// Shift the input buffer 2 positions to the left
for (int i = 0; i < len - 2; i++) {
input[i] = input[i + 2];
}

// Null-terminate the new string
input[len - 2] = '\0';

// Update the length to reflect the removal of the first two characters
len -= 2;
}

echo("Debug: Xon: %d", uart_xon);
// process_line(input, len);
if (uart_xon) {
process_line(input, len);
}
}
}

Expand All @@ -395,6 +449,7 @@ void app_main() {
uart_driver_install(UART_NUM_0, BUFFER_SIZE * 2, 0, 0, NULL, 0);
uart_enable_pattern_det_baud_intr(UART_NUM_0, '\n', 1, 9, 0, 0);
uart_pattern_queue_reset(UART_NUM_0, 100);
uart_xon = true;

printf("\nReady.\n");

Expand Down Expand Up @@ -430,6 +485,10 @@ void app_main() {
run_step(module);
}
}
if (adress_mode && !uart_xon) {
continue;
}

run_step(core_module);

for (auto const &rule : Global::rules) {
Expand Down
11 changes: 11 additions & 0 deletions main/modules/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ void Core::call(const std::string method_name, const std::vector<ConstExpression
arguments[2]->evaluate_string(),
};
xTaskCreate(ota::ota_task, "ota_task", 8192, params, 5, nullptr);
} else if (method_name == "store") {
Module::expect(arguments, 1, integer);
if (arguments[0]->evaluate_number() < 1 || arguments[0]->evaluate_number() > 255) {
throw std::runtime_error("Core: ID out of range");
}
uint8_t id = arguments[0]->evaluate_number();
Storage::put_device_id(id);
} else if (method_name == "get") { // debug
Module::expect(arguments, 0);
echo("i am debug, remove me");
echo("device_id: %d", Storage::get_device_id());
} else {
Module::call(method_name, arguments);
}
Expand Down
6 changes: 6 additions & 0 deletions main/modules/expander.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ void Expander::call(const std::string method_name, const std::vector<ConstExpres
if (!success) {
throw std::runtime_error("could not flash expander \"" + this->name + "\"");
}
} else if (method_name == "xoff") { // debug
Module::expect(arguments, 0);
this->serial->write_checked_line("\x13", 1);
} else if (method_name == "xon") { // debug
Module::expect(arguments, 0);
this->serial->write_checked_line("\x11", 1);
} else {
static char buffer[1024];
int pos = std::sprintf(buffer, "core.%s(", method_name.c_str());
Expand Down
81 changes: 81 additions & 0 deletions main/modules/external_expander.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "external_expander.h"

#include "storage.h"
#include "utils/serial-replicator.h"
#include "utils/timing.h"
#include "utils/uart.h"
#include <cstring>

const char XON = 0x11;
const char XOFF = 0x13;
const char FILTER_MODE = 0x80;
const char ID = 0x81;

ExternalExpander::ExternalExpander(const std::string name,
const ConstSerial_ptr serial,
const uint8_t device_id,
MessageHandler message_handler)
: Module(external_expander, name), serial(serial), device_id(device_id), message_handler(message_handler) {
serial->enable_line_detection();
char buffer[1024] = "";
int len = 0;
const unsigned long int start = millis();
do {
if (millis_since(start) > 1000) {
echo("warning: external 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));
echo("Ready.");
serial->write_checked_line(&FILTER_MODE, 1);
}

void ExternalExpander::step() {
static char buffer[1024];
this->serial->write_checked_line_id(this->device_id, &XON, 1);
while (this->serial->has_buffered_lines()) {
int len = this->serial->read_line(buffer);
check(buffer, len);
if (buffer[0] == '!' && buffer[1] == '!') { // debug todo: Add tag to the message to identify the source -> !! to !!<source>MSG
/* Don't trigger keep-alive from expander updates */
this->message_handler(&buffer[2], false, true);
// echo("received message from %s: %s", this->name.c_str(), &buffer[2]); // debug
} else {
echo("%s: %s", this->name.c_str(), buffer); // debug
}
}
this->serial->write_checked_line_id(this->device_id, &XOFF, 1);
Module::step();
}

void ExternalExpander::call(const std::string method_name, const std::vector<ConstExpression_ptr> arguments) {
if (method_name == "run") {
Module::expect(arguments, 1, string);
std::string command = arguments[0]->evaluate_string();
this->serial->write_checked_line_id(this->device_id, &XON, 1);
this->serial->write_checked_line_id(this->device_id, command.c_str(), command.size());
this->serial->write_checked_line_id(this->device_id, &XOFF, 1);
echo("%s: %s", this->name.c_str(), command.c_str()); // Echo the command
} else if (method_name == "disconnect") {
Module::expect(arguments, 0);
this->serial->deinstall();
echo("%s: disconnected", this->name.c_str()); // Echo the disconnection
} else if (method_name == "filter") { // debug -> actives filter mode
Module::expect(arguments, 0);
this->serial->write_checked_line(&FILTER_MODE, 1);
} else {
static char buffer[1024];
int pos = std::sprintf(buffer, "core.%s(", method_name.c_str());
pos += write_arguments_to_buffer(arguments, &buffer[pos]);
pos += std::sprintf(&buffer[pos], ")");
this->serial->write_checked_line_id(this->device_id, &XON, 1);
this->serial->write_checked_line_id(this->device_id, buffer, pos);
this->serial->write_checked_line_id(this->device_id, &XOFF, 1);
echo("%s: %s", this->name.c_str(), buffer); // Echo the generic command
}
}
22 changes: 22 additions & 0 deletions main/modules/external_expander.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include "module.h"
#include "serial.h"
#include <string>

class ExternalExpander;
using ExternalExpander_ptr = std::shared_ptr<ExternalExpander>;

class ExternalExpander : public Module {
public:
const ConstSerial_ptr serial;
const uint8_t device_id;
MessageHandler message_handler;

ExternalExpander(const std::string name,
const ConstSerial_ptr serial,
const uint8_t device_id,
MessageHandler message_handler);
void step() override;
void call(const std::string method_name, const std::vector<ConstExpression_ptr> arguments) override;
};
11 changes: 11 additions & 0 deletions main/modules/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "dunker_motor.h"
#include "dunker_wheels.h"
#include "expander.h"
#include "external_expander.h"
#include "imu.h"
#include "input.h"
#include "linear_motor.h"
Expand Down Expand Up @@ -79,6 +80,16 @@ 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 == "ExternalExpander") {
Module::expect(arguments, 2, identifier, 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);
uint8_t device_id = arguments[1]->evaluate_integer();
return std::make_shared<ExternalExpander>(name, serial, device_id, message_handler);
} else if (type == "Bluetooth") {
Module::expect(arguments, 1, string);
std::string device_name = arguments[0]->evaluate_string();
Expand Down
1 change: 1 addition & 0 deletions main/modules/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ enum ModuleType {
dunker_wheels,
analog,
proxy,
external_expander,
};

class Module;
Expand Down
40 changes: 37 additions & 3 deletions main/modules/proxy.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include "proxy.h"
#include "driver/uart.h"
#include "uart.h"
#include <memory>

Proxy::Proxy(const std::string name,
const std::string expander_name,
const std::string module_type,
const Expander_ptr expander,
const std::vector<ConstExpression_ptr> arguments)
: Module(proxy, name), expander(expander) {
: Module(proxy, name), expander(expander), external_expander(nullptr) {
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 @@ -25,12 +26,39 @@ Proxy::Proxy(const std::string name,
expander->serial->write_checked_line(buffer, pos);
}

Proxy::Proxy(const std::string &name,
const std::string &expander_name,
const std::string &module_type,
std::shared_ptr<ExternalExpander> external_expander,
const std::vector<ConstExpression_ptr> &arguments)
: Module(proxy, name), expander(nullptr), external_expander(external_expander) {
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]);
pos += std::sprintf(&buffer[pos], "); ");
pos += std::sprintf(&buffer[pos], "%s.broadcast()", name.c_str());

if (module_type == "Input") {
this->properties["level"] = std::make_shared<IntegerVariable>(0);
this->properties["active"] = std::make_shared<BooleanVariable>(false);
}
external_expander->serial->write_checked_line_id(external_expander->device_id, "\x11", 1);
external_expander->serial->write_checked_line_id(external_expander->device_id, buffer, pos);
external_expander->serial->write_checked_line_id(external_expander->device_id, "\x13", 1);
}

void Proxy::call(const std::string method_name, const std::vector<ConstExpression_ptr> arguments) {
static char buffer[256];
int pos = std::sprintf(buffer, "%s.%s(", this->name.c_str(), method_name.c_str());
pos += write_arguments_to_buffer(arguments, &buffer[pos]);
pos += std::sprintf(&buffer[pos], ")");
this->expander->serial->write_checked_line(buffer, pos);
if (expander) {
expander->serial->write_checked_line(buffer, pos);
} else if (external_expander) {
external_expander->serial->write_checked_line_id(external_expander->device_id, "\x11", 1);
external_expander->serial->write_checked_line_id(external_expander->device_id, buffer, pos);
external_expander->serial->write_checked_line_id(external_expander->device_id, "\x13", 1);
}
}

void Proxy::write_property(const std::string property_name, const ConstExpression_ptr expression, const bool from_expander) {
Expand All @@ -41,7 +69,13 @@ void Proxy::write_property(const std::string property_name, const ConstExpressio
static char buffer[256];
int pos = std::sprintf(buffer, "%s.%s = ", this->name.c_str(), property_name.c_str());
pos += expression->print_to_buffer(&buffer[pos]);
this->expander->serial->write_checked_line(buffer, pos);
if (expander) {
expander->serial->write_checked_line(buffer, pos);
} else if (external_expander) {
external_expander->serial->write_checked_line_id(external_expander->device_id, "\x11", 1);
external_expander->serial->write_checked_line_id(external_expander->device_id, buffer, pos);
external_expander->serial->write_checked_line_id(external_expander->device_id, "\x13", 1);
}
}
Module::get_property(property_name)->assign(expression);
}
Loading