【问题标题】:How to list all 'romtable' modules built-in into currently running NodeMCU firmware?如何列出当前运行的 NodeMCU 固件中内置的所有“romtable”模块?
【发布时间】:2021-05-06 14:58:18
【问题描述】:

这个问题和标题一样,差不多就是这样。

固件当然知道它里面有什么。这是 NodeMCU 的“欢迎”信息:

NodeMCU ESP32 built on nodemcu-build.com provided by frightanic.com
        branch: dev-esp32
        commit: fb12af06e7e01f699d68496b80dae481e355adb7
        SSL: false
        modules: adc,can,dac,file,gpio,i2c,ledc,net,node,ow,sigma_delta,spi,time,tmr,touch,uart,wifi
 build 2021-02-01-23-53-37 powered by Lua 5.1.4 on ESP-IDF v3.3-beta1-1391-g9e70825d1 on SDK IDF
lua: cannot open init.lua
>

我很乐意得到逗号分隔的“模块”字符串。

由于内置模块通常以其名称提供,作为全局变量,它有点类似于 Lua 中的“如何列出所有全局变量”,正如我所料,每个人都在普通 Lua 上使用它来检查所有内容,包括像 math 这样的内置插件。然而,这里不一样。我查过了。

从 _G 中列出全局变量不会显示变量的存在,例如 tmruart

> =tmr
romtable: 0x3f406e30

> =uart
romtable: 0x3f40acc8

> for k,v in pairs(_G) do print(k.." : "..tostring(v)) end
module : function: 0x3ffc2fa0
require : function: 0x3ffc2fd4
pairs : function: 0x3ffba950
newproxy : function: 0x3ffc90b4
package : table: 0x3ffba8fc
_G : table: 0x3ffc29c0
_VERSION : Lua 5.1
ipairs : function: 0x3ffba888

> for k,v in pairs(package.preload) do print(k.." : "..tostring(v)) end
((nothing!))

> for k,v in pairs(package.loaded) do print(k.." : "..tostring(v)) end
package
_G

如您所见,tmruart 名称已被识别,但它们并未列为 _G 的内容。

有趣的是,即使 math 也没有在 _G 中列出,尽管它显然是可用的:

> =math
romtable: 0x3f420ef0
> =_G.math
romtable: 0x3f420ef0
> =math.PI
nil
> =math.pi
3.1415926535898

是什么让我想到,好吧,那些tmruart 呢?是的,同样的:

> =_G.tmr
romtable: 0x3f406e30
> =_G.uart
romtable: 0x3f40acc8

我们有它。它们没有在 _G 的内容中列出,但它们是可用的。

我不是 Lua 和 NodeMCU 方面的专家,我可能遗漏了一些东西,但是翻阅了文档,尝试了各种 Lua 运行时检查方法,我只是不知道是否/如何从 _G 中列出它们。

我感觉 _G 有两个单独的元方法,一个用于列出,一个用于访问/获取,并且只有后一个由固件修补以实际按名称提供模块,而前者没有修补以列出它们,但这只是一个猜测。

作为旁注,我在 ESP32 上的 NodeMCU 上遇到了这个问题,dev-esp32 版本(在https://nodemcu-build.com/ 上可用),但是当我写这篇文章时,我在 ESP8288 上尝试了同样的方法,结果是同理:math、tmr、uart 直接可用,通过_G 可用,但在查看_G 的内容时没有列出。

作为旁注#2,经过数小时的搜索,我找到了this video 'ESP8266 NodeMCU - How to know NodeMCU firmware Module info? ',它显示了一个“NodeMCU_firmware_info.lua”,也称为“AEW_NodeMCU_info.lua”(可能是品牌问题),它实际上只包含一个列表名称-变量对,并遍历对各种模块的所有硬编码引用,尝试每个模块的 nil 值..

是的,我知道这会奏效。这正是我想要避免的。我想读出内置信息,而无需硬编码或暴力破解名称!


编辑:按照 koyaanisqatsi 的建议,我检查了 _G 的元表和 __index,结果是romtable。这是一个转储:

function printtable(t) for k,v in pairs(t) do print(k.." : "..tostring(v)) end end

> printtable(getmetatable(_G))
__index : romtable: 0x3f4218b8

> printtable(getmetatable(_G)['__index'])
assert : lightfunction: 0x40156de8
collectgarbage : lightfunction: 0x40156be8
dofile : lightfunction: 0x40156bac
error : lightfunction: 0x40156b60
gcinfo : lightfunction: 0x40156b44
getfenv : lightfunction: 0x40156b14
getmetatable : lightfunction: 0x40156e8c
loadfile : lightfunction: 0x401570f4
load : lightfunction: 0x40156da4
loadstring : lightfunction: 0x40157120
next : lightfunction: 0x40156aec
pcall : lightfunction: 0x40156600
print : lightfunction: 0x40156a44
rawequal : lightfunction: 0x40156a1c
rawget : lightfunction: 0x401569f8
rawset : lightfunction: 0x4015694c
select : lightfunction: 0x401568f4
setfenv : lightfunction: 0x40156874
setmetatable : lightfunction: 0x4015677c
tonumber : lightfunction: 0x401566e0
tostring : lightfunction: 0x40156cfc
type : lightfunction: 0x401566bc
unpack : lightfunction: 0x40156638
xpcall : lightfunction: 0x401565bc
__metatable : romtable: 0x3f421b28

所以,至少有一些内置函数最终出现了,但遗憾的是,这两个模块都没有出现,甚至没有标准的mathdebug


编辑:我还检查了我的 ESP8266 上的外观。

开机信息:

        branch: release
        commit: 64bbf006898109b936fcc09478cbae9d099885a8
        release: 3.0-master_20200910
        release DTS: 202009090323
        SSL: false
        build type: float
        LFS: 0x40000 bytes total capacity
        modules: adc,bit,cron,encoder,file,gpio,gpio_pulse,i2c,net,node,ow,pwm2,rtctime,sigma_delta,sntp,softuart,spi,tmr,wifi
 build 2020-10-10 21:38 powered by Lua 5.1.4 on SDK 3.0.1-dev(fce080e)

和_G的元表:

printtable(getmetatable(_G)['__index'])
string : table: 0x402710e0
table : table: 0x402704cc
debug : table: 0x402719b0
coroutine : table: 0x40271694
math : table: 0x40270d04
ROM : table: 0x3ffef580
assert : function: 0x402424cc
......
......
net : table: 0x40274e9c
sntp : table: 0x40275268
bit : table: 0x40275398
adc : table: 0x40275494
gpio : table: 0x402756e4
tmr : table: 0x40275880
ow : table: 0x40275b04
softuart : table: 0x40275cd8
cron : table: 0x40275e2c
gpiopulse : table: 0x40276120

事实上,内置模块确实会出现在这里。 现在,这是一个难题,为什么他们不在 ESP32 上?

【问题讨论】:

  • 元方法__index可以保存不可见的函数——如果是有函数的表——你有getmetatable()debug.getmetatable()——那就试试:for k,v in pairs(getmetatable(_G).__index) do print(k.." : "..tostring(v)) end
  • @koyaanisqatsi _G 是它自己的元表。 _G.__index 不是表,因此您无法对其进行迭代
  • 我不确定您是否可以从 Lua 访问此信息。你为什么需要这个?我需要知道某个模块是否存在的唯一原因是因为我想使用它。因此,如果我已经知道要使用什么,我可以简单地检查是否可用。
  • 通常 - 如果有人设置它,那么 __index 可以是一个包含全局变量的影子表容器 - 试试看:setmetatable(_G,{__index=table}) 然后所有表函数都是全局的,如 _G.concat(arg)
  • @koyaanisqatsi 我知道如何使用元表。但_G.__index 是 NodeMCU 固件中的一个功能。所以pairs(getmetatable(_G).__index) 会引发错误。 NodeMCU 中也没有标准的debug

标签: lua esp8266 esp32 nodemcu firmware


【解决方案1】:

我找到了!耶!

谢谢@koyaanisqatsi。
您关于 _G 元表中的 __index 的建议是正确的,并且对于 ESP8266 的 NodeMCU 3.0.0 固件是 100% 完美的,并且几乎是带有 dev-esp32 fb12af06e7e01f699d68496b80dae481e355adb7 固件的 ESP32 解决方案的一半。

在 ESP8266 上,这会检索我想查看的所有键(与其他条目混合,但这是次要的一点):

function printtable(t) for k,v in pairs(t) do print(k.." : "..tostring(v)) end end

printtable(getmetatable(_G)['__index'])

string : table: 0x402710e0
table : table: 0x402704cc
debug : table: 0x402719b0
coroutine : table: 0x40271694
math : table: 0x40270d04
ROM : table: 0x3ffef580
assert : function: 0x402424cc
collectgarbage : function: 0x40242230
dofile : function: 0x402421d0
error : function: 0x40242180
gcinfo : function: 0x40242158
getfenv : function: 0x4024211c
getmetatable : function: 0x40242598
loadfile : function: 0x40242890
load : function: 0x4024246c
loadstring : function: 0x402428c8
next : function: 0x402420e4
pcall : function: 0x40241ac4
print : function: 0x4024203c
rawequal : function: 0x40241ff8
rawget : function: 0x40241fc4
rawset : function: 0x40241f8c
select : function: 0x40241ea4
setfenv : function: 0x40241e18
setmetatable : function: 0x40241ce4
tonumber : function: 0x40241be0
tostring : function: 0x402423a4
type : function: 0x40241bac
unpack : function: 0x40241b0c
xpcall : function: 0x40241a74
pwm2 : table: 0x402723b4
encoder : table: 0x402724b4
rtctime : table: 0x40272660
i2c : table: 0x4027282c
spi : table: 0x40272a30
sigma_delta : table: 0x40272af8
node : table: 0x40273398
pipe : table: 0x402735f8
file : table: 0x40273a20
wifi : table: 0x4027472c
net : table: 0x40274e9c
sntp : table: 0x40275268
bit : table: 0x40275398
adc : table: 0x40275494
gpio : table: 0x402756e4
tmr : table: 0x40275880
ow : table: 0x40275b04
softuart : table: 0x40275cd8
cron : table: 0x40275e2c
gpiopulse : table: 0x40276120

如您所见,stringdebug 等内置模块首先列出,然后所有可选模块(如owtmr)在最后。当然,pairs()不能保证订单。

然后,在 ESP32 的固件上,这段代码只显示了一些内置函数,如 getmetatabletonumber,但没有显示任何模块。但是,事实证明,__indexromtable 而不是函数,它本身可以有另一个元表!

这一次我得到了我想要检查的东西,它甚至已经从所有其他噪音中清除了,它只是模块!

function printtable(t) for k,v in pairs(t) do print(k.." : "..tostring(v)) end end

> printtable( getmetatable(getmetatable(_G)['__index'])['__index'] )
time : romtable: 0x3f403458
ow : romtable: 0x3f403600
net : romtable: 0x3f403c60
touch : romtable: 0x3f404a08
node : romtable: 0x3f405218
spi : romtable: 0x3f405570
sigma_delta : romtable: 0x3f405638
ledc : romtable: 0x3f405978
file : romtable: 0x3f405eb0
gpio : romtable: 0x3f406290
can : romtable: 0x3f406578
i2c : romtable: 0x3f406820
wifi : romtable: 0x3f406b78
tmr : romtable: 0x3f406e30
dac : romtable: 0x3f406fc8
adc : romtable: 0x3f407118
uart : romtable: 0x3f40acc8
string : romtable: 0x3f4212a8
table : romtable: 0x3f421ef0
debug : romtable: 0x3f421cc8
coroutine : romtable: 0x3f4217d0
math : romtable: 0x3f420ef0
ROM : romtable: 0x3f422ac8

当然,如果我们有第一个,然后是第二个元表,我必须检查我们是否可以更深入 - 而不是,它是 nil。

> =getmetatable(getmetatable(getmetatable(_G)['__index'])['__index'])
nil

无论如何,非常感谢koyaanisqatsi小猪


编辑:正如 Marcel 在评论中指出的那样,在 ESP8266 上它实际上就像

> = node.info('build_config')['modules']
adc,can,dac,file,gpio,i2c,ledc,net,node,ow,sigma_delta,spi,time,tmr,touch,uart,wifi

但是,目前这在 ESP32 上是不可能的,因为 node.info() 尚未实现。在那之前,我的双 getmetatable 解决方法非常有用。

【讨论】:

  • 供参考 - 在 Lua 5.3.5 中,我意识到字符串的元方法 __index 填充了所有字符串函数 - 所以我查看整数,但它们没有 __index 和数学函数 - 使用 __index一张表显示所有未知的内容都将在 __index 中搜索 - 因此我的建议 - 这只是在森林中的一个镜头;-) - 因为我从未使用过任何 NodeMCU 或 ESPXXX - 但这次我会看看它
  • @koyaanisqatsi 如果您喜欢修补电子设备等,我建议先使用 ESP32 模型。带有预装 LUA 的 ESP8266 的 NodeMCU 板非常容易启动和试用,但它......感觉受限。可能只是我在优化 LUA 代码方面缺乏技巧,但是新鲜和干净的模块,新鲜的固件,还没有脚本,最多有 ~40kB 的可用 RAM 内存,并且连接到 WiFi,发布一个简单的网络服务器,可能真的很快就把它吃光了.添加一些功能,添加一些 HTML 生成器,然后突然内存不足。
  • 但是,我并不是很喜欢设置一个火柴盒大小的网络服务器,我只是在玩,在一些基本的事情之后就被内存不足感到惊讶。在构建 FW 时,我可能也添加了太多模块。这一切都在快速吞噬记忆。我玩过 GPIO 和一辆 RC Car,令我惊讶的是……它似乎有很多 IO 引脚,但其中很多是无法使用的,而且只有其中一些在启动时是“干净的”。 IE。如果某个引脚在 ESP 启动时发出了一些噪音,那么以后它可能是一个超级重复的 GPIO,但我不能将它直接连接到电机驱动器,否则汽车会在启动时摆动/驱动!
  • 一篇关于 ESP8266 的 GPIO 的非常好的文章,几乎所有的 GPIO 都必须小心使用 rabbithole.wwwdotorg.org/2017/03/28/esp8266-gpio.html 另一方面,一个非常相似的板,带有 ESP32-WROOM/etc 的 NodeMCU,只是一点点更昂贵,似乎从 13 个干净的 GPIO 开始,至少有 12 个需要小心使用,并且 dev-esp32 固件包含随机选择的所有有趣模块,留下超过 300kB 的免费片上 RAM,更不用说 ESP32 -带有外部 ~4MB RAM 的 WROVER 模块! thingpulse.com/esp32-how-to-use-psram 不过我是 ESP32 的新手。还需要验证。
  • 尽管如此,用于 ESP32 的 NodeMCU FW 仍处于“开发”阶段。不是“发布”,也不是“稳定”,没有像 NodeMCU FW for ESP8266 那样在该领域进行多年测试,所以请慎重花钱;)
猜你喜欢
  • 2020-07-10
  • 2010-12-20
  • 2010-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多