【发布时间】: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 中列出全局变量不会显示变量的存在,例如 tmr 或 uart。
> =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
如您所见,tmr 和 uart 名称已被识别,但它们并未列为 _G 的内容。
有趣的是,即使 math 也没有在 _G 中列出,尽管它显然是可用的:
> =math
romtable: 0x3f420ef0
> =_G.math
romtable: 0x3f420ef0
> =math.PI
nil
> =math.pi
3.1415926535898
是什么让我想到,好吧,那些tmr 和uart 呢?是的,同样的:
> =_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
所以,至少有一些内置函数最终出现了,但遗憾的是,这两个模块都没有出现,甚至没有标准的math 或debug。
编辑:我还检查了我的 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