Skip to content
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
53 changes: 43 additions & 10 deletions platforms/Arduino/Arduino.ino.template
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,19 @@
#include "Arduino.h"
#include "bin/upload.h"

unsigned int wasm_len = upload_wasm_len;
unsigned char* wasm = upload_wasm;
struct ModuleInfo {
unsigned char* wasm;
unsigned int wasm_len;
const char* name;
};

ModuleInfo modules[] = {
{upload_wasm, upload_wasm_len, "main"},
};
const size_t module_count = sizeof(modules) / sizeof(modules[0]);

WARDuino* wac = WARDuino::instance();
std::vector<Module*> loaded_modules;
Module* m;

#define UART_PIN 3
Expand Down Expand Up @@ -52,20 +61,44 @@ void setup(void) {
Serial.println(ESP.getFreePsram());
}

void loop() {
m = wac->load_module(wasm, wasm_len, {});
void loop() {

for (size_t i = 0; i < module_count; i++) {
Serial.print("Loading module: ");
Serial.println(modules[i].name);

Module* mod = wac->load_module(
modules[i].wasm,
modules[i].wasm_len,
modules[i].name
);

if (mod) {
loaded_modules.push_back(mod);
m = mod;
} else {
Serial.print(" ✗ Failed to load ");
Serial.println(modules[i].name);
}
}

printf("LOADED \n\n");
{{PAUSED}}
xTaskCreate(startDebuggerStd, "Debug Thread", 5000, NULL, 1, NULL);

disableCore0WDT();
printf("START\n\n");
Serial.println("START\n");

Serial.println("\nFree heap:");
Serial.println(ESP.getFreeHeap());

wac->run_module(m);
printf("END\n\n");
wac->unload_module(m);
}
if (m) {
wac->run_module(m);
}

Serial.println("END\n");

for (auto mod : loaded_modules) {
wac->unload_module(mod);
}
loaded_modules.clear();
}
183 changes: 128 additions & 55 deletions platforms/CLI-Emulator/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,15 @@ void print_help() {
print_version();
fprintf(stdout, "\n");
fprintf(stdout, "Usage:\n");
fprintf(stdout, " wdcli <file> [options]\n");
fprintf(stdout, " wdcli <main-module> [options]\n");
fprintf(stdout, "\n");
fprintf(stdout, "Arguments:\n");
fprintf(stdout, " <main-module> Main WebAssembly module to execute\n");
fprintf(stdout, "\n");
fprintf(stdout, "Options:\n");
fprintf(stdout,
" --link <file> Link additional module(s) (can be specified "
"multiple times)\n");
fprintf(stdout,
" --loop Let the runtime loop infinitely on exceptions "
"(default: false)\n");
Expand Down Expand Up @@ -71,9 +78,21 @@ void print_help() {
"(default: interpreter)\n");
fprintf(stdout, " --invoke Invoke a function from the module\n");
fprintf(stdout, " --version Get version information\n");
fprintf(stdout, " --help Show this help message\n");
}

std::string getModuleName(const char *path) {
std::string p(path);
size_t lastSlash = p.find_last_of("/\\");
std::string filename =
(lastSlash == std::string::npos) ? p : p.substr(lastSlash + 1);
size_t lastDot = filename.find_last_of(".");
if (lastDot != std::string::npos) return filename.substr(0, lastDot);
return filename;
}

Module *load(WARDuino wac, const char *file_name, Options opt) {
Module *load(WARDuino *wac, const char *file_name, const char *module_name,
Options opt) {
uint8_t *wasm;
unsigned int file_size;

Expand Down Expand Up @@ -104,8 +123,7 @@ Module *load(WARDuino wac, const char *file_name, Options opt) {
}
fclose(file);
file = nullptr;

return wac.load_module(wasm, file_size, opt);
return wac->load_module(wasm, file_size, module_name, opt);

error:
fclose(file);
Expand Down Expand Up @@ -261,45 +279,48 @@ StackValue parseParameter(const char *input, uint8_t value_type) {
int main(int argc, const char *argv[]) {
ARGV_SHIFT(); // Skip command name

// Configuration
bool return_exception = true;
bool no_debug = false;
bool no_socket = false;
const char *socket = "8192";
bool initiallyPaused = false;
const char *file_name = nullptr;
const char *main_module = nullptr;
std::vector<const char *> linked_modules;
const char *proxy = nullptr;
const char *baudrate = nullptr;
const char *mode = "interpreter";
bool dump_info = false;

const char *fname = nullptr;
std::vector<StackValue> arguments = std::vector<StackValue>();
const char *invoke_fname = nullptr;
std::vector<const char *> invoke_raw_args;

// Parse main module (first positional argument)
if (argc > 0 && argv[0][0] != '-') {
ARGV_GET(file_name);

dbg_info("=== LOAD MODULE INTO WARDUINO ===\n");
m = load(*wac, file_name,
{.disable_memory_bounds = false,
.mangle_table_index = false,
.dlsym_trim_underscore = false,
.return_exception = return_exception});
main_module = argv[0];
ARGV_SHIFT();
}

// Parse options
while (argc > 0) {
const char *arg = argv[0];
if (arg[0] != '-') {
break;
}

ARGV_SHIFT();
if (!strcmp("--version", arg)) {
print_version();
return 0;
} else if (!strcmp("--help", arg)) {
} else if (!strcmp("--help", arg) || !strcmp("-h", arg)) {
print_help();
return 0;
} else if (!strcmp("--link", arg)) {
const char *link_file = nullptr;
ARGV_GET(link_file);
if (link_file) {
linked_modules.push_back(link_file);
} else {
fprintf(stderr, "wdcli: --link requires a file argument\n");
return 1;
}
} else if (!strcmp("--loop", arg)) {
return_exception = false;
} else if (!strcmp("--no-debug", arg)) {
Expand All @@ -311,47 +332,98 @@ int main(int argc, const char *argv[]) {
} else if (!strcmp("--paused", arg)) {
initiallyPaused = true;
} else if (!strcmp("--proxy", arg)) {
ARGV_GET(proxy); // /dev/ttyUSB0
ARGV_GET(proxy);
} else if (!strcmp("--baudrate", arg)) {
ARGV_GET(baudrate);
} else if (!strcmp("--mode", arg)) {
ARGV_GET(mode);
} else if (!strcmp("--invoke", arg)) {
ARGV_GET(fname);

// find function
int fidx = wac->get_export_fidx(m, fname);
if (fidx < 0) {
fprintf(stderr, "wdcli: no exported function with name '%s'\n",
fname);
return 1;
}

Block function = m->functions[fidx];

// consume all arguments for the function
for (uint32_t i = 0; i < function.type->param_count; ++i) {
const char *number = nullptr;
ARGV_GET(number);

if (number[0] == '-') {
FATAL("wdcli: wrong number of arguments for '%s'\n", fname);
}

arguments.push_back(
parseParameter(number, function.type->params[i]));
ARGV_GET(invoke_fname);
// Collect remaining args as potential parameters until next flag
while (argc > 0 && argv[0][0] != '-') {
const char *val;
ARGV_GET(val);
invoke_raw_args.push_back(val);
}
} else if (!strcmp("--dump-info", arg)) {
dump_info = true;
} else {
fprintf(stderr, "wdcli: unknown option '%s'\n", arg);
fprintf(stderr, "Try 'wdcli --help' for more information.\n");
return 1;
}
}

if (argc != 0 || file_name == nullptr) {
print_help();
if (main_module == nullptr) {
fprintf(stderr, "wdcli: no main module specified\n");
fprintf(stderr, "Usage: wdcli <main-module> [options]\n");
fprintf(stderr, "Try 'wdcli --help' for more information.\n");
return 1;
}

m->warduino = wac;
dbg_info("=== LOAD MODULES INTO WARDUINO ===\n");
std::vector<Module *> loaded_modules;

for (const char *file_path : linked_modules) {
std::string modName = getModuleName(file_path);
Module *new_mod = load(wac, file_path, modName.c_str(),
{.disable_memory_bounds = false,
.mangle_table_index = false,
.dlsym_trim_underscore = false,
.return_exception = return_exception});

if (new_mod) {
new_mod->warduino = wac;
loaded_modules.push_back(new_mod);
dbg_info(" Loaded linked module: %s\n", modName.c_str());
} else {
fprintf(stderr, "wdcli: failed to load linked module '%s'\n",
file_path);
return 1;
}
}

// Load main module last
std::string mainModName = getModuleName(main_module);
m = load(wac, main_module, mainModName.c_str(),
{.disable_memory_bounds = false,
.mangle_table_index = false,
.dlsym_trim_underscore = false,
.return_exception = return_exception});

if (m) {
m->warduino = wac;
loaded_modules.push_back(m);
dbg_info(" Loaded main module: %s\n", mainModName.c_str());
} else {
fprintf(stderr, "wdcli: failed to load main module '%s'\n",
main_module);
return 1;
}

std::vector<StackValue> parsed_args;
if (invoke_fname != nullptr) {
int fidx = wac->get_export_fidx(m, invoke_fname);
if (fidx < 0) {
fprintf(stderr, "wdcli: no exported function with name '%s'\n",
invoke_fname);
return 1;
}
Block function = m->functions[fidx];

if (invoke_raw_args.size() != function.type->param_count) {
FATAL(
"wdcli: wrong number of arguments for '%s' (expected %d, got "
"%zu)\n",
invoke_fname, function.type->param_count,
invoke_raw_args.size());
}

for (uint32_t i = 0; i < function.type->param_count; ++i) {
parsed_args.push_back(
parseParameter(invoke_raw_args[i], function.type->params[i]));
}
}

if (initiallyPaused) {
wac->debugger->pauseRuntime(m);
Expand Down Expand Up @@ -388,12 +460,11 @@ int main(int argc, const char *argv[]) {
json["primitive_fidx_mapping"] = fidx_mapping;

std::cout << json << std::endl;
wac->unload_module(m);
for (auto mod : loaded_modules) wac->unload_module(mod);
exit(0);
}

if (strcmp(mode, "proxy") == 0) {
// Run in proxy mode
wac->debugger->proxify();
} else if (proxy) {
// Connect to proxy device
Expand Down Expand Up @@ -443,19 +514,21 @@ int main(int argc, const char *argv[]) {
options.no_socket = no_socket;
options.socket = std::stoi(socket);
setupDebuggerCommunication(options);

communication = std::thread(startDebuggerCommunication);
}

// Run Wasm module
dbg_info("\n=== STARTED INTERPRETATION (main thread) ===\n");
if (fname != nullptr) {
uint32_t fidx = wac->get_export_fidx(m, fname);
wac->invoke(m, fidx, arguments.size(), &arguments[0]);
if (invoke_fname != nullptr) {
uint32_t fidx = wac->get_export_fidx(m, invoke_fname);
wac->invoke(m, fidx, parsed_args.size(), parsed_args.data());
} else {
wac->run_module(m);
}
wac->unload_module(m);

// Unload all
for (auto mod : loaded_modules) {
wac->unload_module(mod);
}
wac->debugger->stop();

if (!no_debug) {
Expand All @@ -464,4 +537,4 @@ int main(int argc, const char *argv[]) {
}

return 0;
}
}
Loading