summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcheapie <no-email-for-you@example.com>2022-01-02 18:42:08 -0600
committercheapie <no-email-for-you@example.com>2022-01-02 18:42:08 -0600
commit243a8063ddbb107ab191aa333cc6cdc85701f410 (patch)
tree848d72cd8b91cc9d259f75196bfd577bd8e88e66
parent648f77bd43f1fbe59e6d655e57d96e2647a43b68 (diff)
downloadmesecons-243a8063ddbb107ab191aa333cc6cdc85701f410.tar
mesecons-243a8063ddbb107ab191aa333cc6cdc85701f410.tar.gz
mesecons-243a8063ddbb107ab191aa333cc6cdc85701f410.tar.bz2
mesecons-243a8063ddbb107ab191aa333cc6cdc85701f410.tar.xz
mesecons-243a8063ddbb107ab191aa333cc6cdc85701f410.zip
Add Luacontroller examples/help system
-rw-r--r--mesecons_luacontroller/docmanager.lua86
-rw-r--r--mesecons_luacontroller/examples/clock.lua7
-rw-r--r--mesecons_luacontroller/examples/counter.lua11
-rw-r--r--mesecons_luacontroller/examples/rslatch.lua18
-rw-r--r--mesecons_luacontroller/help/digilines.txt18
-rw-r--r--mesecons_luacontroller/help/events.txt12
-rw-r--r--mesecons_luacontroller/help/interrupts.txt22
-rw-r--r--mesecons_luacontroller/help/introduction.txt8
-rw-r--r--mesecons_luacontroller/help/luafunctions.txt60
-rw-r--r--mesecons_luacontroller/help/mesecons.txt24
-rw-r--r--mesecons_luacontroller/help/terminal.txt18
-rw-r--r--mesecons_luacontroller/init.lua46
12 files changed, 327 insertions, 3 deletions
diff --git a/mesecons_luacontroller/docmanager.lua b/mesecons_luacontroller/docmanager.lua
new file mode 100644
index 0000000..ad7b2d4
--- /dev/null
+++ b/mesecons_luacontroller/docmanager.lua
@@ -0,0 +1,86 @@
+mesecon.lc_docs = {}
+
+--Other mods can place their own examples in here.
+--The table key will be used as the name.
+mesecon.lc_docs.examples = {}
+
+minetest.register_on_mods_loaded(function()
+ --Build a list of example names so that the order will stay the same when the formspecs are redrawn
+ mesecon.lc_docs.example_order = {}
+ for k in pairs(mesecon.lc_docs.examples) do
+ table.insert(mesecon.lc_docs.example_order,k)
+ end
+ table.sort(mesecon.lc_docs.example_order)
+end)
+
+function mesecon.lc_docs.generate_example_formspec(sel_index)
+ sel_index = math.max(sel_index,1)
+ sel_index = math.min(sel_index,#mesecon.lc_docs.example_order)
+ local selected_text = mesecon.lc_docs.examples[mesecon.lc_docs.example_order[sel_index]]
+ local fs = "textlist[0.25,0.6;3,9.05;example_list;"
+ for _,i in ipairs(mesecon.lc_docs.example_order) do
+ fs = fs..minetest.formspec_escape(i)..","
+ end
+ fs = string.sub(fs,1,-2)..";"..sel_index..";false]"
+ .."textarea[3.25,0.6;11.5,8.05;;;"..minetest.formspec_escape(selected_text).."]"
+ return fs
+end
+
+local included_examples = {
+ ["R/S Latch"] = "rslatch.lua",
+ ["Clock"] = "clock.lua",
+ ["LCD Counter"] = "counter.lua",
+}
+
+for k,v in pairs(included_examples) do
+ local f = io.open(minetest.get_modpath("mesecons_luacontroller")..DIR_DELIM.."examples"..DIR_DELIM..v,"r")
+ mesecon.lc_docs.examples[k] = f:read("*all")
+ f:close()
+end
+
+--Other mods can provide their own help pages too, but the order of these must be specified and is not automatically sorted.
+--In this table, the key is a number representing the position in the list, and the value is the description.
+mesecon.lc_docs.help_order = {}
+--In this table, the key is the description and the value in the content.
+mesecon.lc_docs.help_pages = {}
+
+function mesecon.lc_docs.generate_help_formspec(sel_index)
+ sel_index = math.max(sel_index,1)
+ sel_index = math.min(sel_index,#mesecon.lc_docs.help_order)
+ local selected_text = mesecon.lc_docs.help_pages[mesecon.lc_docs.help_order[sel_index]]
+ local fs = "textlist[0.25,0.6;3,9.05;help_list;"
+ for _,i in ipairs(mesecon.lc_docs.help_order) do
+ fs = fs..minetest.formspec_escape(i)..","
+ end
+ fs = string.sub(fs,1,-2)..";"..sel_index..";false]"
+ .."textarea[3.25,0.6;11.5,9.05;;;"..minetest.formspec_escape(selected_text).."]"
+ return fs
+end
+
+local included_help_order = {
+ "Introduction",
+ "Events",
+ "Lua Functions",
+ "Mesecons I/O",
+ "Terminal I/O",
+ "Digilines I/O",
+ "Interrupts",
+}
+
+local included_help_content = {
+ ["Introduction"] = "introduction.txt",
+ ["Events"] = "events.txt",
+ ["Lua Functions"] = "luafunctions.txt",
+ ["Mesecons I/O"] = "mesecons.txt",
+ ["Terminal I/O"] = "terminal.txt",
+ ["Digilines I/O"] = "digilines.txt",
+ ["Interrupts"] = "interrupts.txt",
+}
+
+for _,v in ipairs(included_help_order) do
+ local filename = included_help_content[v]
+ local f = io.open(minetest.get_modpath("mesecons_luacontroller")..DIR_DELIM.."help"..DIR_DELIM..filename,"r")
+ table.insert(mesecon.lc_docs.help_order,v)
+ mesecon.lc_docs.help_pages[v] = f:read("*all")
+ f:close()
+end
diff --git a/mesecons_luacontroller/examples/clock.lua b/mesecons_luacontroller/examples/clock.lua
new file mode 100644
index 0000000..262aac2
--- /dev/null
+++ b/mesecons_luacontroller/examples/clock.lua
@@ -0,0 +1,7 @@
+--Interrupt-Driven Clock
+--Continually pulses pin A, turning on/off once per second.
+
+if event.type == "program" or event.iid == "clock" then
+ port.a = not port.a
+ interrupt(1,"clock",true)
+end
diff --git a/mesecons_luacontroller/examples/counter.lua b/mesecons_luacontroller/examples/counter.lua
new file mode 100644
index 0000000..bbb974c
--- /dev/null
+++ b/mesecons_luacontroller/examples/counter.lua
@@ -0,0 +1,11 @@
+--LCD Counter (requires digilines)
+--Counts the number of pulses sent to pin A and displays the number on an LCD.
+--Connect the LCD over digilines and set the channel to "lcd"
+
+if event.type == "program" then
+ mem.count = 0
+elseif event.type == "on" and event.pin.name == "A" then
+ mem.count = mem.count + 1
+end
+
+digiline_send("lcd",tostring(mem.count))
diff --git a/mesecons_luacontroller/examples/rslatch.lua b/mesecons_luacontroller/examples/rslatch.lua
new file mode 100644
index 0000000..1257396
--- /dev/null
+++ b/mesecons_luacontroller/examples/rslatch.lua
@@ -0,0 +1,18 @@
+--R/S Latch
+--When S is active, Q turns on.
+--When R is active, Q turns off.
+--/Q is always the opposite of Q.
+
+--Pin Assignments:
+-- S: Pin A
+-- R: Pin B
+-- Q: Pin C
+--/Q: Pin D
+
+if pin.a then
+ port.c = true
+elseif pin.b then
+ port.c = false
+end
+
+port.d = not port.c
diff --git a/mesecons_luacontroller/help/digilines.txt b/mesecons_luacontroller/help/digilines.txt
new file mode 100644
index 0000000..85d1076
--- /dev/null
+++ b/mesecons_luacontroller/help/digilines.txt
@@ -0,0 +1,18 @@
+Digilines
+=========
+
+If the digilines mod is installed, then Luacontrollers can also send/receive digilines signals.
+
+To send a digilines signal, use the digiline_send() function.
+Example:
+digiline_send("lcd","Hello") --Sends the message "Hello" on the channel "lcd"
+
+Please note that digilines messages are sent from all pins, and there is no need or ability to select one.
+
+When a digilines signal is received, an event occurs.
+Example:
+{
+ type = "digiline",
+ channel = "lcd",
+ msg = "Hello"
+}
diff --git a/mesecons_luacontroller/help/events.txt b/mesecons_luacontroller/help/events.txt
new file mode 100644
index 0000000..cd2bcef
--- /dev/null
+++ b/mesecons_luacontroller/help/events.txt
@@ -0,0 +1,12 @@
+Events
+======
+
+Unlike some other types of programs, Luacontroller programs cannot run continously.
+Instead, they run whenever something (an event) happens, and an "event" table is made available with details.
+
+Event types include:
+* 'program' - Program was loaded
+* 'on' and 'off' - A Mesecons pin changed on/off state
+* 'digiline' (if Digilines is installed) - A Digilines message was received
+* 'interrupt' - An interrupt timer reached zero
+* 'terminal' - Text was typed into the terminal
diff --git a/mesecons_luacontroller/help/interrupts.txt b/mesecons_luacontroller/help/interrupts.txt
new file mode 100644
index 0000000..3c5e54f
--- /dev/null
+++ b/mesecons_luacontroller/help/interrupts.txt
@@ -0,0 +1,22 @@
+Interrupts
+==========
+
+Interrupts allow you to schedule an event to occur later. You can also specify an interrupt ID (IID) for use in keeping track of multiple pending interrupts at the same time.
+
+To schedule an interrupt, use the interrupt() function.
+Example:
+interrupt(5,"test") --In 5 seconds, an interrupt will occur with the IID "test"
+
+Setting a third parameter to true will cause the interrupt to be "lightweight", where timing stops if the mapblock containing the Luacontroller is unloaded, and automatically resumes when it is loaded again. This stops machines from continously running when no players are in the area.
+Example:
+interrupt(5,"test",true) --Same as above, but lightweight
+
+Lightweight mode does have a few differences - timing resolution is limited to one second, however pending interrupts can also be canceled by specifying a nil time and the same IID as previously.
+Some servers may force all interrupts to be lightweight.
+
+When an interrupt's time expires, an event occurs.
+Example:
+{
+ type = "interrupt",
+ iid = "test"
+}
diff --git a/mesecons_luacontroller/help/introduction.txt b/mesecons_luacontroller/help/introduction.txt
new file mode 100644
index 0000000..253ddd4
--- /dev/null
+++ b/mesecons_luacontroller/help/introduction.txt
@@ -0,0 +1,8 @@
+Luacontroller Introduction
+==========================
+
+Welcome! This device is a Luacontroller (or "LuaC" for short), which is an advanced microcontroller capable of interacting with many devices and performing complex processing.
+
+As the name suggests, the Lua programming language is used to program this device.
+If you aren't familiar with Lua, a tutorial/reference can be found here:
+http://lua-users.org/wiki/TutorialDirectory
diff --git a/mesecons_luacontroller/help/luafunctions.txt b/mesecons_luacontroller/help/luafunctions.txt
new file mode 100644
index 0000000..8c39529
--- /dev/null
+++ b/mesecons_luacontroller/help/luafunctions.txt
@@ -0,0 +1,60 @@
+Lua Functions
+=============
+
+The following Lua functions are available in a Luacontroller:
+
+From the string library:
+* byte
+* char
+* format
+* len
+* lower
+* upper
+* rep (restricted)
+* reverse
+* sub
+* find (restricted)
+
+From the math library:
+* abs
+* acos
+* asin
+* atan
+* atan2
+* ceil
+* cos
+* cosh
+* deg
+* exp
+* floor
+* fmod
+* frexp
+* ldexp
+* log
+* log10
+* max
+* min
+* modf
+* pow
+* rad
+* random
+* sin
+* sinh
+* sqrt
+* tan
+* tanh
+
+From the table library:
+* concat
+* insert
+* maxn
+* remove
+* sort
+
+From the os library:
+* clock
+* difftime
+* time
+
+Other:
+* print
diff --git a/mesecons_luacontroller/help/mesecons.txt b/mesecons_luacontroller/help/mesecons.txt
new file mode 100644
index 0000000..8b8d562
--- /dev/null
+++ b/mesecons_luacontroller/help/mesecons.txt
@@ -0,0 +1,24 @@
+Mesecons I/O
+============
+
+Luacontrollers provide four pins for mesecons connections, labeled from A to D.
+There is no need to manually switch between input and output modes - any pin not outputting mesecons power automatically works as an input.
+
+Input states can be read from the pin table.
+Example:
+if pin.a then
+ --Code here would be run only if pin A is active
+end
+
+Outputs can be set by writing to the port table.
+Example:
+port.b = true --Outputs a signal on pin B
+
+When a pin starts or stops receiving a signal, an event occurs with some information about the pin.
+Example:
+{
+ type = "on",
+ pin = {
+ name = "A"
+ }
+}
diff --git a/mesecons_luacontroller/help/terminal.txt b/mesecons_luacontroller/help/terminal.txt
new file mode 100644
index 0000000..9b23eed
--- /dev/null
+++ b/mesecons_luacontroller/help/terminal.txt
@@ -0,0 +1,18 @@
+Terminal I/O
+============
+
+Simple text I/O is available on the "terminal" tab.
+
+To send text to the Luacontroller, enter the message into the field provided, then press enter or click the send button.
+An event will occur containing the text entered.
+Example:
+{
+ type = "terminal",
+ text = "apt moo"
+}
+
+To display a message on the terminal, use the print() function.
+Example:
+print("Have you mooed today?")
+
+Errors and warnings are also displayed on the terminal.
diff --git a/mesecons_luacontroller/init.lua b/mesecons_luacontroller/init.lua
index da38c7f..500bbbd 100644
--- a/mesecons_luacontroller/init.lua
+++ b/mesecons_luacontroller/init.lua
@@ -28,6 +28,9 @@
-- (see where local env is defined)
-- Something nice to play is is appending minetest.env to it.
+--Load the documentation manager, which provides examples and library information
+dofile(minetest.get_modpath("mesecons_luacontroller")..DIR_DELIM.."docmanager.lua")
+
local BASENAME = "mesecons_luacontroller:luacontroller"
local rules = {
@@ -220,7 +223,7 @@ local function update_formspec(pos)
local code = minetest.formspec_escape(meta:get_string("code"))
local errmsg = minetest.formspec_escape(meta:get_string("errmsg"))
local tab = meta:get_int("tab")
- if tab < 1 or tab > 2 then tab = 1 end
+ if tab < 1 or tab > 4 then tab = 1 end
--Default theme settings
local textcolor = "#ffffff"
@@ -241,7 +244,7 @@ local function update_formspec(pos)
.."style_type[label,textarea,field;font=mono]"
.."style_type[textarea;textcolor="..textcolor.."]"
.."background[0,0;15,12;"..bg_img.."]"
- .."tabheader[0,0;tab;Code,Terminal;"..tab.."]"
+ .."tabheader[0,0;tab;Code,Terminal,Help,Examples;"..tab.."]"
.."image_button_exit[14.5,0;0.425,0.4;"..close_img..";exit;]"
if tab == 1 then
@@ -257,6 +260,13 @@ local function update_formspec(pos)
.."button[12.75,9.85;2,1;terminal_send;Send]"
.."button[12.75,10.85;2,1;terminal_clear;Clear]"
.."field_close_on_enter[terminal_input;false]"
+ elseif tab == 3 then
+ --Help tab
+ fs = fs..mesecon.lc_docs.generate_help_formspec(meta:get_int("help_selidx"))
+ elseif tab == 4 then
+ --Examples tab
+ fs = fs..mesecon.lc_docs.generate_example_formspec(meta:get_int("example_selidx"))
+ .."image_button[6.25,10.25;2.5,1;"..run_img..";program_example;]"
end
meta:set_string("formspec",fs)
@@ -938,7 +948,7 @@ local function on_receive_fields(pos, form_name, fields, sender)
update_formspec(pos)
else
local tab = meta:get_int("tab")
- if tab < 1 or tab > 2 then tab = 1 end
+ if tab < 1 or tab > 4 then tab = 1 end
if tab == 1 then
--Code tab
if not fields.program then
@@ -969,6 +979,36 @@ local function on_receive_fields(pos, form_name, fields, sender)
return
end
run(pos,{type="terminal",text=fields.terminal_input})
+ elseif tab == 3 then
+ --Help tab
+ if fields.help_list then
+ local event = minetest.explode_textlist_event(fields.help_list)
+ if event.type == "CHG" then
+ meta:set_int("help_selidx",event.index)
+ update_formspec(pos)
+ end
+ end
+ elseif tab == 4 then
+ --Examples tab
+ if fields.example_list then
+ local event = minetest.explode_textlist_event(fields.example_list)
+ if event.type == "CHG" then
+ meta:set_int("example_selidx",event.index)
+ update_formspec(pos)
+ end
+ elseif fields.program_example then
+ local name = sender:get_player_name()
+ if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
+ minetest.record_protection_violation(pos, name)
+ return
+ end
+ local selidx = meta:get_int("example_selidx")
+ selidx = math.max(1,math.min(selidx,#mesecon.lc_docs.example_order))
+ local code = mesecon.lc_docs.examples[mesecon.lc_docs.example_order[selidx]]
+ meta:set_string("terminal_text","")
+ meta:set_int("tab",1)
+ set_program(pos,code)
+ end
end
end
end