Compare commits
14 Commits
bf83b7495d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 57f83bd56b | |||
| 5890c68d8e | |||
| facaef5983 | |||
| 256a7ecca6 | |||
| 4f8df39b69 | |||
| e41caf713c | |||
| c80f0fed9a | |||
| 8c1048698d | |||
| 903a8baf87 | |||
| e77752efae | |||
| 4e6b83a456 | |||
| f6dd0bd669 | |||
| 06f5605e3d | |||
| 2fa9be5ebf |
@@ -1,16 +1,27 @@
|
||||
local kernel = require("kernel")
|
||||
local monitor = kernel.addDriver("monitor-driver")
|
||||
local data = kernel.addDriver("disk-driver")
|
||||
local taskManager = require("task-manager")
|
||||
local monitor = require("monitor-driver")
|
||||
local data = require("disk-driver")
|
||||
local speaker = require("speaker-driver")
|
||||
|
||||
local chat = kernel.addProgram("chat")
|
||||
local gps = kernel.addProgram("gps")
|
||||
|
||||
|
||||
local function run()
|
||||
monitor.initialize()
|
||||
data.initialize()
|
||||
speaker.initialize()
|
||||
|
||||
monitor.writeLine("Starting system...")
|
||||
monitor.writeLine("System started successfully!")
|
||||
computerName = data.getRead("computer-name")
|
||||
os.setComputerLabel(computerName)
|
||||
monitor.writeLine("Computer name: " .. computerName)
|
||||
|
||||
taskManager.addProgram("Communication", chat);
|
||||
taskManager.addProgram("GPS", gps);
|
||||
taskManager.listPrograms()
|
||||
end
|
||||
|
||||
return { run = run }
|
||||
41
kernel.lua
41
kernel.lua
@@ -1,3 +1,5 @@
|
||||
|
||||
|
||||
local function addDriver(fileName)
|
||||
local extension = ".lua"
|
||||
local fullFile = fileName .. extension
|
||||
@@ -18,4 +20,41 @@ local function addFolderDriver(folder, fileName)
|
||||
return require(fileName)
|
||||
end
|
||||
|
||||
return { addDriver = addDriver, addFolderDriver = addFolderDriver }
|
||||
local function addProgram(fileName)
|
||||
local extension = ".lua"
|
||||
local fullFile = fileName .. extension
|
||||
shell.execute("rm", fullFile)
|
||||
local baseRoute = "https://git.astrocore.space/root/nova-corp/raw/branch/main/"
|
||||
shell.execute("wget", baseRoute .. "programs" .. "/" .. fullFile)
|
||||
sleep(2)
|
||||
return require(fileName)
|
||||
end
|
||||
|
||||
local function addSound(fileName)
|
||||
local extension = ".dfpwm"
|
||||
local fullFile = fileName .. extension
|
||||
shell.execute("rm", fullFile)
|
||||
local baseRoute = "https://git.astrocore.space/root/nova-corp/raw/branch/main/"
|
||||
shell.execute("wget", baseRoute .. "sounds" .. "/" .. fullFile)
|
||||
sleep(2)
|
||||
return
|
||||
end
|
||||
|
||||
local function addServerHandler(fileName)
|
||||
local extension = ".lua"
|
||||
local fullFile = fileName .. extension
|
||||
shell.execute("rm", fullFile)
|
||||
local baseRoute = "https://git.astrocore.space/root/nova-corp/raw/branch/main/"
|
||||
shell.execute("wget", baseRoute .. "server" .. "/" .. fullFile)
|
||||
sleep(2)
|
||||
return require(fileName)
|
||||
end
|
||||
|
||||
|
||||
addDriver("task-manager")
|
||||
addDriver("monitor-driver")
|
||||
addDriver("disk-driver")
|
||||
addDriver("speaker-driver")
|
||||
|
||||
|
||||
return { addDriver = addDriver, addFolderDriver = addFolderDriver, addProgram = addProgram, addSound = addSound, addServerHandler = addServerHandler }
|
||||
70
programs/chat.lua
Normal file
70
programs/chat.lua
Normal file
@@ -0,0 +1,70 @@
|
||||
local modem = peripheral.find("modem")
|
||||
local speaker = require("speaker-driver")
|
||||
local SERVER_PORT = 100
|
||||
local CLIENT_PORT = 101
|
||||
|
||||
local username = os.getComputerLabel() or ("User" .. os.getComputerID())
|
||||
|
||||
local function start()
|
||||
if modem then
|
||||
modem.open(CLIENT_PORT)
|
||||
modem.transmit(SERVER_PORT, CLIENT_PORT, { type = "join", username = username })
|
||||
end
|
||||
print("Chat program started as " .. username)
|
||||
end
|
||||
|
||||
local function stop()
|
||||
if modem then
|
||||
modem.transmit(SERVER_PORT, CLIENT_PORT, { type = "leave", username = username })
|
||||
modem.close(CLIENT_PORT)
|
||||
end
|
||||
print("Chat program stopped.")
|
||||
end
|
||||
|
||||
local function restart()
|
||||
stop()
|
||||
start()
|
||||
end
|
||||
|
||||
local function receiveLoop()
|
||||
while true do
|
||||
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
||||
if channel == CLIENT_PORT and type(message) == "table" then
|
||||
local x, y = term.getCursorPos()
|
||||
term.setCursorPos(1, y)
|
||||
term.clearLine()
|
||||
|
||||
if message.type == "system" then
|
||||
print("[System] " .. message.content)
|
||||
speaker.play("notification")
|
||||
elseif message.type == "chat" then
|
||||
print(message.username .. ": " .. message.content)
|
||||
speaker.play("notification")
|
||||
speaker.playTTSFile(message.content)
|
||||
end
|
||||
|
||||
write("> ")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function sendLoop()
|
||||
while true do
|
||||
write("> ")
|
||||
local input = read()
|
||||
if modem then
|
||||
modem.transmit(SERVER_PORT, CLIENT_PORT, { type = "chat", username = username, content = input })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function main()
|
||||
if not modem then
|
||||
print("No modem attached")
|
||||
while true do os.pullEvent() end
|
||||
end
|
||||
|
||||
parallel.waitForAny(receiveLoop, sendLoop)
|
||||
end
|
||||
|
||||
return { start = start, stop = stop, restart = restart, main = main }
|
||||
24
programs/gps.lua
Normal file
24
programs/gps.lua
Normal file
@@ -0,0 +1,24 @@
|
||||
local function start()
|
||||
print("GPS program started.")
|
||||
end
|
||||
|
||||
local function stop()
|
||||
print("GPS program stopped.")
|
||||
end
|
||||
|
||||
local function restart()
|
||||
stop()
|
||||
start()
|
||||
end
|
||||
|
||||
local function main()
|
||||
print("Chat main loop running...")
|
||||
while true do
|
||||
local event = os.pullEvent()
|
||||
if event == "char" then
|
||||
print("GPS Char")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return { start = start, stop = stop, restart = restart, main = main }
|
||||
51
server/chat-server.lua
Normal file
51
server/chat-server.lua
Normal file
@@ -0,0 +1,51 @@
|
||||
local modem = peripheral.find("modem")
|
||||
local SERVER_PORT = 100
|
||||
local CLIENT_PORT = 101
|
||||
|
||||
local function log(msg)
|
||||
print("[Server]: " .. tostring(msg))
|
||||
end
|
||||
|
||||
local function broadcast(message)
|
||||
if modem then
|
||||
modem.transmit(CLIENT_PORT, SERVER_PORT, message)
|
||||
end
|
||||
end
|
||||
|
||||
local function handleMessage(event, side, channel, replyChannel, message, distance)
|
||||
if type(message) == "table" then
|
||||
if message.type == "join" then
|
||||
log(message.username .. " connected.")
|
||||
broadcast({ type = "system", content = message.username .. " joined the chat." })
|
||||
elseif message.type == "leave" then
|
||||
log(message.username .. " disconnected.")
|
||||
broadcast({ type = "system", content = message.username .. " left the chat." })
|
||||
elseif message.type == "chat" then
|
||||
log(message.username .. ": " .. message.content)
|
||||
broadcast({ type = "chat", username = message.username, content = message.content })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function listenLoop()
|
||||
if not modem then
|
||||
log("No modem found!")
|
||||
return
|
||||
end
|
||||
modem.open(SERVER_PORT)
|
||||
log("Listening on port " .. SERVER_PORT)
|
||||
|
||||
while true do
|
||||
local eventData = {os.pullEvent("modem_message")}
|
||||
-- event, side, channel, replyChannel, message, distance
|
||||
if eventData[3] == SERVER_PORT then
|
||||
handleMessage(table.unpack(eventData))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function main()
|
||||
parallel.waitForAll(listenLoop)
|
||||
end
|
||||
|
||||
return { main = main }
|
||||
12
server/main.lua
Normal file
12
server/main.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
local kernel = require("kernel")
|
||||
local chat = kernel.addServerHandler("chat-server")
|
||||
|
||||
|
||||
local function run()
|
||||
print("Starting Server...")
|
||||
local tasks = {}
|
||||
table.insert(tasks, chat.main)
|
||||
parallel.waitForAll(table.unpack(tasks))
|
||||
end
|
||||
|
||||
return { run = run }
|
||||
7
server/startup.lua
Normal file
7
server/startup.lua
Normal file
@@ -0,0 +1,7 @@
|
||||
shell.execute("rm", "kernel.lua")
|
||||
shell.execute("wget", "https://git.astrocore.space/root/nova-corp/raw/branch/main/kernel.lua")
|
||||
sleep(5)
|
||||
local kernel = require("kernel")
|
||||
local main = kernel.addFolderDriver("server", "main")
|
||||
main.run()
|
||||
|
||||
BIN
sounds/notification.dfpwm
Normal file
BIN
sounds/notification.dfpwm
Normal file
Binary file not shown.
98
speaker-driver.lua
Normal file
98
speaker-driver.lua
Normal file
@@ -0,0 +1,98 @@
|
||||
local speaker = peripheral.find("speaker")
|
||||
local dfpwm = require("cc.audio.dfpwm")
|
||||
local encoder = dfpwm.make_encoder()
|
||||
local decoder = dfpwm.make_decoder()
|
||||
|
||||
local sounds = {
|
||||
{name = "notification", file = "notification.dfpwm"}
|
||||
}
|
||||
|
||||
local function initialize()
|
||||
kernel = require("kernel")
|
||||
kernel.addSound("notification")
|
||||
speaker = peripheral.find("speaker")
|
||||
if not speaker then
|
||||
print("Warning: No speaker attached.")
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function play(name)
|
||||
if not speaker then return false end
|
||||
|
||||
local filePath
|
||||
for _, sound in ipairs(sounds) do
|
||||
if sound.name == name then
|
||||
filePath = sound.file
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not filePath then
|
||||
print("Sound '" .. name .. "' not defined.")
|
||||
return false
|
||||
end
|
||||
|
||||
if not fs.exists(filePath) then
|
||||
print("File '" .. filePath .. "' not found.")
|
||||
return false
|
||||
end
|
||||
|
||||
-- Create a new decoder for this playback to reset state
|
||||
local decoder = dfpwm.make_decoder()
|
||||
|
||||
for chunk in io.lines(filePath, 16 * 1024) do
|
||||
local buffer = decoder(chunk)
|
||||
while not speaker.playAudio(buffer, 3.0) do
|
||||
os.pullEvent("speaker_audio_empty")
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
----------------
|
||||
|
||||
local function getFileName(name)
|
||||
local extension = ".dfpwm"
|
||||
local fullFile = name .. extension
|
||||
return fullFile
|
||||
end
|
||||
|
||||
local function randomFileName()
|
||||
local name = ""
|
||||
for i = 1, 12 do
|
||||
name = name .. string.char(math.random(97, 122)) -- a–z
|
||||
end
|
||||
return name
|
||||
end
|
||||
|
||||
local function playSound(fileName)
|
||||
local fileStream = getFileName(fileName)
|
||||
local values = io.lines(fileStream, 16 * 1024)
|
||||
for input in values do
|
||||
local decoded = decoder(input)
|
||||
while not speaker.playAudio(decoded, 3.0) do
|
||||
os.pullEvent("speaker_audio_empty")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function playTTSFile(value)
|
||||
local message = textutils.urlEncode(value)
|
||||
local url = "http://api.astrocore.space/api/TextToSpeech?message=" .. message
|
||||
local response, err = http.get { url = url, binary = true }
|
||||
local name = randomFileName()
|
||||
local fileName = name .. ".dfpwm"
|
||||
|
||||
local fileData = response.readAll()
|
||||
local file = fs.open(fileName,"w")
|
||||
file.write(fileData)
|
||||
file.close()
|
||||
response.close()
|
||||
playSound(name)
|
||||
shell.execute("rm", fileName)
|
||||
end
|
||||
|
||||
return { initialize = initialize, play = play, playTTSFile = playTTSFile }
|
||||
146
task-manager.lua
Normal file
146
task-manager.lua
Normal file
@@ -0,0 +1,146 @@
|
||||
local monitor = peripheral.find("monitor")
|
||||
local programs = {}
|
||||
local isRunning = false
|
||||
|
||||
|
||||
local function addProgram(name, program)
|
||||
table.insert(programs, {name = name, program = program})
|
||||
end
|
||||
|
||||
local function runProgram(programOrPath)
|
||||
local programModule
|
||||
|
||||
if type(programOrPath) == "string" then
|
||||
if fs.exists(programOrPath) then
|
||||
-- Load the file as a chunk. In Lua 5.2+ use the env parameter instead of setfenv.
|
||||
local env = _ENV or _G
|
||||
local programChunk, err = loadfile(programOrPath, "t", env)
|
||||
if not programChunk then
|
||||
print("Error loading program: " .. err)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Run the chunk to get the module table
|
||||
local success, result = pcall(programChunk)
|
||||
|
||||
if not success then
|
||||
print("Error executing program file: " .. tostring(result))
|
||||
return false
|
||||
end
|
||||
programModule = result
|
||||
else
|
||||
print("Program not found: " .. programOrPath)
|
||||
return false
|
||||
end
|
||||
elseif type(programOrPath) == "table" then
|
||||
programModule = programOrPath
|
||||
else
|
||||
print("Invalid program type")
|
||||
return false
|
||||
end
|
||||
|
||||
if type(programModule) ~= "table" or not programModule.main then
|
||||
print("Error: Program must return a table with at least a 'main' function.")
|
||||
return false
|
||||
end
|
||||
|
||||
-- Setup Monitor
|
||||
local w, h = monitor.getSize()
|
||||
monitor.setBackgroundColor(colors.black)
|
||||
monitor.clear()
|
||||
|
||||
-- Draw X button
|
||||
monitor.setCursorPos(w, 1)
|
||||
monitor.setBackgroundColor(colors.red)
|
||||
monitor.setTextColor(colors.white)
|
||||
monitor.write("X")
|
||||
monitor.setBackgroundColor(colors.black)
|
||||
|
||||
-- Create window for program
|
||||
local win = window.create(monitor, 1, 2, w, h - 1)
|
||||
local oldTerm = term.redirect(win)
|
||||
|
||||
-- Lifecycle: START
|
||||
if programModule.start then
|
||||
local ok, err = pcall(programModule.start)
|
||||
if not ok then
|
||||
print("Error in start(): " .. tostring(err))
|
||||
term.redirect(oldTerm)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- Lifecycle: MAIN (Run in parallel with exit watcher)
|
||||
local function runMain()
|
||||
-- We wrap main in pcall to catch errors without crashing the driver
|
||||
local ok, err = pcall(programModule.main)
|
||||
if not ok then
|
||||
win.setTextColor(colors.red)
|
||||
win.write("Runtime Error: " .. tostring(err))
|
||||
sleep(2) -- Let user see error
|
||||
end
|
||||
end
|
||||
|
||||
local function watchExit()
|
||||
while true do
|
||||
local _, _, x, y = os.pullEvent("monitor_touch")
|
||||
if x == w and y == 1 then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
parallel.waitForAny(runMain, watchExit)
|
||||
|
||||
-- Lifecycle: STOP
|
||||
if programModule.stop then
|
||||
pcall(programModule.stop)
|
||||
end
|
||||
|
||||
term.redirect(oldTerm)
|
||||
return true
|
||||
end
|
||||
|
||||
local function exitProgram()
|
||||
isRunning = false
|
||||
end
|
||||
|
||||
local function drawList()
|
||||
monitor.clear()
|
||||
monitor.setCursorPos(1, 1)
|
||||
monitor.write("Available Programs:")
|
||||
|
||||
for i, program in ipairs(programs) do
|
||||
monitor.setCursorPos(1, i + 2) -- Start from line 3
|
||||
monitor.write(i .. ". " .. program.name)
|
||||
end
|
||||
|
||||
monitor.setCursorPos(1, #programs + 4)
|
||||
monitor.write("Click to run")
|
||||
end
|
||||
|
||||
local function listPrograms()
|
||||
isRunning = true
|
||||
while isRunning do
|
||||
drawList()
|
||||
|
||||
local event, side, x, y = os.pullEvent("monitor_touch")
|
||||
local programIndex = y - 2
|
||||
|
||||
if programIndex > 0 and programIndex <= #programs then
|
||||
local program = programs[programIndex]
|
||||
monitor.clear()
|
||||
monitor.setCursorPos(1,1)
|
||||
monitor.write("Running " .. program.name .. "...")
|
||||
sleep(0.5)
|
||||
runProgram(program.program)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
addProgram = addProgram,
|
||||
runProgram = runProgram,
|
||||
exitProgram = exitProgram,
|
||||
listPrograms = listPrograms
|
||||
}
|
||||
Reference in New Issue
Block a user