esp8266 运行 在后台下载二进制文件
esp8266 run downloaded binary in background
剧情简介:
我所有基于 ESP8266 / 32 的设备(我有大约 1000 个)都在读取传感器,进行一些边缘计算并将数据发送回中央服务器。
然而大部分时间他们都在闲置。
所以我在想是否可能出现以下情况:
- 我编写了一个从服务器轮询任务的库
- 如果找到任务,则下载该任务
- 任务 运行 在 ESP 后台(主循环逻辑的后台)
- 任务完成后,数据将发送回任务服务器
问题围绕第 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_CHUNK1
或 STATE_CHUNK3
。
ESP8266 还有另一个 SDK,叫做 "RTOS" SDK - Realtime OS - docs for it here。它可能更适合做你想做的事。您仍然无法使用 fork()
或抢占式多任务处理,但它更加异步并且具有允许您将代码分解为单独任务的编程模型,它将 运行你。缺点是它比 Arduino 环境更复杂,文档也更少,您几乎肯定必须完全重写现有代码才能使用它。
剧情简介:
我所有基于 ESP8266 / 32 的设备(我有大约 1000 个)都在读取传感器,进行一些边缘计算并将数据发送回中央服务器。
然而大部分时间他们都在闲置。
所以我在想是否可能出现以下情况:
- 我编写了一个从服务器轮询任务的库
- 如果找到任务,则下载该任务
- 任务 运行 在 ESP 后台(主循环逻辑的后台)
- 任务完成后,数据将发送回任务服务器
问题围绕第 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_CHUNK1
或 STATE_CHUNK3
。
ESP8266 还有另一个 SDK,叫做 "RTOS" SDK - Realtime OS - docs for it here。它可能更适合做你想做的事。您仍然无法使用 fork()
或抢占式多任务处理,但它更加异步并且具有允许您将代码分解为单独任务的编程模型,它将 运行你。缺点是它比 Arduino 环境更复杂,文档也更少,您几乎肯定必须完全重写现有代码才能使用它。