esp8266 运行 在后台下载二进制文件

esp8266 run downloaded binary in background

剧情简介:

我所有基于 ESP8266 / 32 的设备(我有大约 1000 个)都在读取传感器,进行一些边缘计算并将数据发送回中央服务器。

然而大部分时间他们都在闲置。

所以我在想是否可能出现以下情况:

  1. 我编写了一个从服务器轮询任务的库
  2. 如果找到任务,则下载该任务
  3. 任务 运行 在 ESP 后台(主循环逻辑的后台)
  4. 任务完成后,数据将发送回任务服务器

问题围绕第 3 点。

是否可以在后台 'run' 一个单独的 bin 文件(比如来自 SPIFFS)类似于 linux :

 pid_t pid = fork();
 execv

如果不是(我猜不是),您还有其他选择吗? (类似于后台任务)?

ESP8266 是一款非常简单的处理器。 Linux fork() 有大量的硬件支持,可以为进程提供独立的地址空间并支持抢占式多任务处理。 ESP8266 没有执行此操作的硬件支持,OSs 和 运行s 没有进程模型。所以无论你这样做,你都不会使用 fork().

如果您使用的是 Arduino SDK,那么您也在使用 Arduino SDK 构建的 "Non-OS" SDK。 Non-OS SDK 甚至没有任何任务或协程的内部概念。因此,如果您使用的是 Arduino SDK 或基于非 OS SDK 构建的任何其他 SDK,则需要实现自己的 "background" 处理。

在 Arduino SDK 中,您将重写 loop() 代码,以便它检查是否有正常的前台工作,处理它,然后进行一定数量的后台工作。在回到前台工作之前,您需要决定可以做多少后台工作。您还需要确保后台工作偶尔调用 yield()delay(),这样看门狗定时器就不会触发。

不会很漂亮。

因此您的代码可能类似于:

#define ELAPSED_WORK_TIME (millis() - work_start_time)

// maximum milliseconds before we must check if there's foreground work
// or yield() to keep the watchdog timer happy
#define MAX_WORK_TIME  1000

void loop() {
  while(foreground_work_is_available()) {
    do_foreground_work();
    yield();
  }

  if(background_work_is_available()) {
    unsigned long work_start_time = millis();

    do_some_work();

    if(ELAPSED_WORK_TIME > MAX_WORK_TIME)
      return;

    do_some_more_work();

    if(ELAPSED_WORK_TIME > MAX_WORK_TIME)
      return;
  }
}

或者,如果您可以确定后台代码块不会 运行 太久,您可以在循环中使用状态变量,当您 运行 后台代码块时代码,设置状态变量以指示下一个块 运行 和 return 以允许 loop() 继续。

像这样:

#define STATE_CHUNK1 1
#define STATE_CHUNK2 2
#define STATE_CHUNK3 3
#define STATE_CHUNK4 4

void loop() {
  static int background_work_state = STATE_CHUNK1;

  while(foreground_work_is_available()) {
    do_foreground_work();
    yield();
  }

  switch(loop_state) {
    case STATE_CHUNK1:
      work_chunk1();
      background_work_state = STATE_CHUNK2;
      return;

    case STATE_CHUNK2:
      work_chunk2();
      background_work_state = STATE_CHUNK3;
      return;

    case STATE_CHUNK3:
      work_chunk3();
      background_work_state = STATE_CHUNK3;
      return;

    case STATE_CHUNK4:
      work_chunk4();
      background_work_state = STATE_CHUNK4;
      return;
   }
}

如果需要,您可以使状态机更加复杂。也许 work_chunk2() 会失败,下次你会想回到 work_chunk1() - 然后你会测试它的 return 值来决定是否将 background_work_state 设置为 STATE_CHUNK1STATE_CHUNK3

ESP8266 还有另一个 SDK,叫做 "RTOS" SDK - Realtime OS - docs for it here。它可能更适合做你想做的事。您仍然无法使用 fork() 或抢占式多任务处理,但它更加异步并且具有允许您将代码分解为单独任务的编程模型,它将 运行你。缺点是它比 Arduino 环境更复杂,文档也更少,您几乎肯定必须完全重写现有代码才能使用它。