-- CMC.lua — Command Controller (AtlasOS Shell/CPU v2.0) -- in[1] = cmd_rx ← IOC.out[4] (IN|command) -- in[2] = mem_rx ← MMC.out[1] (FS response) -- out[1] = text_tx → IOC.in[2] (OUT|text) -- out[2] = clear_tx → IOC.in[3] (1 = clear) -- out[3] = color_tx → IOC.in[4] (R,G,B) -- out[4] = mem_tx → MMC.in[1] (FS request) local state = 0 local ST_IDLE = 0 local ST_WAIT_FS = 1 local uid, gid, cwd, curUser = 0, 0, "/", "root" local pendingCmd = nil local lastRespSeq = 0 local function parseMsg(msg) local p = msg:find("|") return p and msg:sub(1, p - 1) or msg, p and msg:sub(p + 1) or nil end local function printOut(t) out[1] = "OUT|" .. tostring(t) end local function printErr(t) out[1] = "OUT|" .. tostring(t) end local function doClear() out[2] = 1 end local function doColor(r, g, b) out[3] = r .. "," .. g .. "," .. b end local function fsReq(op, arg) local msg = op if arg then msg = msg .. "|" .. arg end out[4] = msg end local cmds = {} local function reg(name, fn, desc) cmds[name] = { fn = fn, desc = desc } end reg("help", function(a) local t = "AtlasOS v2.0 commands:\n" for n, e in pairs(cmds) do t = t .. " " .. n .. " " .. e.desc .. "\n" end return t end, "Show help") reg("echo", function(a) if #a == 0 then error("echo: missing text") end return table.concat(a, " ") end, "Echo text") reg("clear", function(a) doClear() end, "Clear screen") reg("color", function(a) if #a < 3 then error("color: need R G B") end local r, g, b = tonumber(a[1]), tonumber(a[2]), tonumber(a[3]) if not (r and g and b) then error("color: invalid values") end r = math.floor(math.max(0, math.min(255, r))) g = math.floor(math.max(0, math.min(255, g))) b = math.floor(math.max(0, math.min(255, b))) doColor(r, g, b) printOut("Color set to " .. r .. "," .. g .. "," .. b) end, "Set color R G B") reg("status", function(a) return "AtlasOS v2.0 | User: " .. curUser .. "(" .. uid .. ") | CWD: " .. cwd end, "System status") reg("ls", function(a) local path = cwd local opts = {} for i = 1, #a do if a[i]:sub(1, 1) == "-" then opts[a[i]] = true else path = a[i] end end pendingCmd = { name = "ls", path = path, opts = opts } state = ST_WAIT_FS fsReq("LS", path) end, "List directory [path]") reg("cat", function(a) if #a == 0 then error("cat: missing path") end pendingCmd = { name = "cat", path = a[1] } state = ST_WAIT_FS fsReq("READ", a[1] .. "|0|8192") end, "Show file content") reg("cd", function(a) local path = a[1] if not path then path = "/" end pendingCmd = { name = "cd", path = path } state = ST_WAIT_FS fsReq("CHDIR", path) end, "Change directory [path]") reg("stat", function(a) if #a == 0 then error("stat: missing path") end pendingCmd = { name = "stat", path = a[1] } state = ST_WAIT_FS fsReq("STAT", a[1]) end, "Show file metadata") local function execCmd(cmdStr) local parts = {} for t in cmdStr:gmatch("%S+") do parts[#parts + 1] = t end if #parts == 0 then return end local name = parts[1] local args = {} for i = 2, #parts do args[#args + 1] = parts[i] end local entry = cmds[name] if not entry then printErr("Unknown: " .. name .. ". Try 'help'.") return end local ok, result = pcall(entry.fn, args) if not ok then printErr(tostring(result)) elseif result ~= nil then printOut(result) end end local function handleFSResponse(op, data) if not pendingCmd then return end local cmd = pendingCmd if op == "ERR" then local code = data or "EIO" if code == "ENOENT" then printErr(cmd.path .. ": No such file or directory") elseif code == "EACCES" then printErr(cmd.path .. ": Permission denied") elseif code == "ENOTDIR" then printErr(cmd.path .. ": Not a directory") elseif code == "EISDIR" then printErr(cmd.path .. ": Is a directory") else printErr(cmd.path .. ": " .. code) end pendingCmd = nil state = ST_IDLE return end if cmd.name == "ls" then local showAll = (cmd.opts["-la"] or cmd.opts["-a"]) local names = {} for n in data:gmatch("([^|]+)") do names[#names + 1] = n end local outLines = {} for _, n in ipairs(names) do if n ~= "." and n ~= ".." or showAll then outLines[#outLines + 1] = n end end if #outLines == 0 then outLines[1] = "(empty)" end printOut(table.concat(outLines, "\n")) elseif cmd.name == "cat" then printOut(data) elseif cmd.name == "cd" then cwd = data printOut(cwd) elseif cmd.name == "stat" then local parts = {} for s in data:gmatch("([^|]+)") do parts[#parts + 1] = s end if #parts >= 6 then local typ = parts[2] == "d" and "directory" or "file" local out = "Inode: " .. parts[1] .. " Type: " .. typ .. "\n" out = out .. "Mode: " .. parts[3] .. " UID: " .. parts[4] .. " GID: " .. parts[5] .. "\n" out = out .. "Size: " .. parts[6] .. " Modified: " .. (parts[7] or "?") printOut(out) else printOut(data) end end pendingCmd = nil state = ST_IDLE end inp = {} function upd() if state == ST_IDLE then if inp[1] ~= nil then local op, cmd = parseMsg(tostring(inp[1])) if op == "IN" and cmd and #cmd > 0 then execCmd(cmd) end end end if state == ST_WAIT_FS and inp[2] ~= nil then local resp = tostring(inp[2]) if #resp > 0 then local op, rest = parseMsg(resp) if op and rest then local seqStr, data = parseMsg(rest) local seq = tonumber(seqStr) or 0 if seq > lastRespSeq then lastRespSeq = seq handleFSResponse(op, data) end end end end table.clear(inp) end