GithubHelp home page GithubHelp logo

invpe / gp-iot Goto Github PK

View Code? Open in Web Editor NEW
0.0 1.0 0.0 67 KB

General Purpose Things eXperiment - dynamically loading and executing binaries while running a Sketch on esp32.

License: MIT License

C++ 81.90% C 5.91% Shell 12.19%
esp32 esp32-arduino experiment iot

gp-iot's Introduction

image

General Purpose Things - eXperiment

As part of an initiative to enhance the GridShell project, i thought about executing binaries instead of scripts by dynamically loading and executing them on ESP32 nodes.

This repo called GP-IOT - General Purpose (Internet of) Things is my workbench, to get me to a place where i can do it issues free, easily and in secure manner.

General Purpose Things - draw inspiration from established distributed computing systems like BOINC, focusing on executing binaries on nodes. This repository introduces a Sketch named Runner, designed to dynamically load binaries from SPIFFS, and a Task source code that is an example binary. It locates the function address within the binary and executes it in a separate thread, showcasing a practical example of dynamic binary execution on IoT devices.

Demo

The repository holds a ready-to-use solution, including Runner sketch and a simple task.

  1. First upload the Runner sketch.
  2. Then go to Example and perform compilation, linkage, binary extraction and spiffs upload with ./task.sh
  3. Open up terminal and reboot your device, you should end up binary being exexuted :
[19:55:29:407] Connecting to WiFi...␍␊
[19:55:29:407] Connected to WiFi␍␊
[19:55:29:523] Loading from SPIFFS␍␊
[19:55:29:527] BIN SIZE: 152␍␊
[19:55:29:527] Free heap size: 201324␍␊
[19:55:29:527] MALLOC OK␍␊
[19:55:29:545] SUBMITTING TASK␍␊
[19:55:29:545] .␍␊
[19:55:29:545] Task Function Address           : 0x14␊
[19:55:29:545] Program buffer address          : 0x40092C9C␊
[19:55:29:545] Calculated Task Function Address: 0x40092CB0␊
[19:55:29:545] Return value from task: AAAAAAAAAA␊

How

There are few conditions that have to be met in order for the example to work:

  1. Binary we want to start needs to have a special metadata structure, that is placed at the END of the binary itself with the use of .ld script.

    This metadata holds a uint32_t address of the function we want to execute, in this case: taskFunction

struct TaskMetadata {    
    uint32_t taskFunctionAddress;       
    char dummyText[16];  
}; 
struct TaskMetadata __attribute__((section(".task_metadata"))) taskMetadata = {    
    (uint32_t)&taskFunction,
    "AAAAAAAAAAAAAAA"  // Initialize dummy text to see if our metadata is seen at the top of the binary
};
  1. The compilation and later link process need to ensure this metadata is placed at the bottom of the binary, because runner sketch will pick this up and retrieve the taskFunctionAddress. I am using a template .ld file for that, might not be perfect but works.

  2. The binary needs to have the same function definition as the runner so that we call it with the same arguments, and expect the same resunts (if anyhting is returned)

typedef void (*task_func_t)(const char*, char*);

void taskFunction(const char* input, char* output)

  1. The binary once compiled must have a decent size, so that we can allocate the memory for it, there is a check performed in the RUNNER sketch, that bails out if execution is impossible due to memory issues.
  // Check if there is enough free heap memory
  if (freeHeap < fileSize) {
    Serial.println("Insufficient free heap memory");
    taskFile.close();
    return;
  }
  1. The binary needs to be placed on SPIFFS, so ensure the SPIFFS is ready for use - that's handled by Runner sketch, which formats and initializes it properly.

  2. The runner (once started) will then dynamically load and execute the binary, but it can be also done in a separate thread to avoid blocking the main one if necessary.

    xTaskCreate(taskRunner, "TaskRunner", 8192, program, 1, NULL);

  3. The code is executed in IRAM, remember variables and addresses are relative to the start of the binary as there is no o/s initialization for this binary blob.

  4. The CPU can access data via the data bus in a byte-, half-word-, or word-aligned manner. The CPU can also access data via the instruction bus, but only in a word-aligned manner; non-word-aligned access will cause a CPU exception.

  5. And probably more.. ;-)

gp-iot's People

Contributors

invpe avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.