v1
This commit is contained in:
195
atlas_os/CMC.lua
195
atlas_os/CMC.lua
@@ -1,45 +1,58 @@
|
|||||||
-- CMC.lua — Command Controller (AtlasOS Shell/CPU v2.0)
|
-- CMC.lua — Command Controller (AtlasOS Shell/CPU v2.0)
|
||||||
-- in[1] = cmd_rx ← IOC.out[4] (IN|command)
|
-- in[1] = cmd_rx ← IOC.out[4] (IN|command)
|
||||||
-- in[2] = mem_rx ← MMC.out[1] (FS response)
|
-- in[2] = mem_rx ← MMC.out[1] (FS response)
|
||||||
-- out[1] = text_tx → IOC.in[2] (OUT|text)
|
-- out[1] = disp_tx → IOC.in[2] (OUT|text / CLR / COL|R,G,B)
|
||||||
-- 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)
|
-- out[4] = mem_tx → MMC.in[1] (FS request)
|
||||||
|
|
||||||
local state = 0
|
|
||||||
local ST_IDLE = 0
|
local ST_IDLE = 0
|
||||||
local ST_WAIT_FS = 1
|
local ST_WAIT_FS = 1
|
||||||
|
local state = ST_IDLE
|
||||||
|
|
||||||
local uid, gid, cwd, curUser = 0, 0, "/", "root"
|
local uid, gid, cwd, curUser = 0, 0, "/", "root"
|
||||||
|
|
||||||
local pendingCmd = nil
|
|
||||||
local lastRespSeq = 0
|
local lastRespSeq = 0
|
||||||
|
|
||||||
|
local outQueue = {}
|
||||||
|
local pendingCmd = nil
|
||||||
|
|
||||||
local function parseMsg(msg)
|
local function parseMsg(msg)
|
||||||
local p = msg:find("|")
|
local p = msg:find("|")
|
||||||
return p and msg:sub(1, p - 1) or msg, p and msg:sub(p + 1) or nil
|
return p and msg:sub(1, p - 1) or msg, p and msg:sub(p + 1) or nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local function printOut(t)
|
local function resolvePath(path)
|
||||||
out[1] = "OUT|" .. tostring(t)
|
if not path or path == "" then return cwd end
|
||||||
end
|
if path:sub(1, 1) == "/" then return path end
|
||||||
|
if cwd:sub(-1) == "/" then return cwd .. path end
|
||||||
local function printErr(t)
|
return cwd .. "/" .. path
|
||||||
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
|
end
|
||||||
|
|
||||||
local function fsReq(op, arg)
|
local function fsReq(op, arg)
|
||||||
local msg = op
|
out[4] = op .. (arg and ("|" .. arg) or "")
|
||||||
if arg then msg = msg .. "|" .. arg end
|
end
|
||||||
out[4] = msg
|
|
||||||
|
-- queue items: op, value (op = "t" text, "c" color, "x" clear)
|
||||||
|
local function qText(v)
|
||||||
|
outQueue[#outQueue + 1] = { "t", tostring(v) }
|
||||||
|
end
|
||||||
|
|
||||||
|
local function qErr(v)
|
||||||
|
outQueue[#outQueue + 1] = { "c", "255,40,40" }
|
||||||
|
outQueue[#outQueue + 1] = { "t", tostring(v) }
|
||||||
|
outQueue[#outQueue + 1] = { "c", "0,255,0" }
|
||||||
|
end
|
||||||
|
|
||||||
|
local function qClear()
|
||||||
|
outQueue[#outQueue + 1] = { "x" }
|
||||||
|
end
|
||||||
|
|
||||||
|
local function qColor(r, g, b)
|
||||||
|
outQueue[#outQueue + 1] = { "c", r .. "," .. g .. "," .. b }
|
||||||
|
end
|
||||||
|
|
||||||
|
local function queueLines(lines)
|
||||||
|
for i = 1, #lines do
|
||||||
|
qText(lines[i])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local cmds = {}
|
local cmds = {}
|
||||||
@@ -49,20 +62,26 @@ local function reg(name, fn, desc)
|
|||||||
end
|
end
|
||||||
|
|
||||||
reg("help", function(a)
|
reg("help", function(a)
|
||||||
local t = "AtlasOS v2.0 commands:\n"
|
local lines = { curUser .. " " .. cwd .. "> help" }
|
||||||
|
lines[#lines + 1] = "AtlasOS v2.0:"
|
||||||
for n, e in pairs(cmds) do
|
for n, e in pairs(cmds) do
|
||||||
t = t .. " " .. n .. " " .. e.desc .. "\n"
|
lines[#lines + 1] = " " .. n .. " " .. e.desc
|
||||||
end
|
end
|
||||||
return t
|
queueLines(lines)
|
||||||
end, "Show help")
|
end, "This help")
|
||||||
|
|
||||||
reg("echo", function(a)
|
reg("echo", function(a)
|
||||||
if #a == 0 then error("echo: missing text") end
|
if #a == 0 then error("echo: missing text") end
|
||||||
return table.concat(a, " ")
|
local out = ""
|
||||||
|
for i = 1, #a do
|
||||||
|
if #out > 0 then out = out .. " " end
|
||||||
|
out = out .. tostring(a[i])
|
||||||
|
end
|
||||||
|
queueLines({ curUser .. " " .. cwd .. "> echo " .. out, out })
|
||||||
end, "Echo text")
|
end, "Echo text")
|
||||||
|
|
||||||
reg("clear", function(a)
|
reg("clear", function(a)
|
||||||
doClear()
|
qClear()
|
||||||
end, "Clear screen")
|
end, "Clear screen")
|
||||||
|
|
||||||
reg("color", function(a)
|
reg("color", function(a)
|
||||||
@@ -72,12 +91,16 @@ reg("color", function(a)
|
|||||||
r = math.floor(math.max(0, math.min(255, r)))
|
r = math.floor(math.max(0, math.min(255, r)))
|
||||||
g = math.floor(math.max(0, math.min(255, g)))
|
g = math.floor(math.max(0, math.min(255, g)))
|
||||||
b = math.floor(math.max(0, math.min(255, b)))
|
b = math.floor(math.max(0, math.min(255, b)))
|
||||||
doColor(r, g, b)
|
qColor(r, g, b)
|
||||||
printOut("Color set to " .. r .. "," .. g .. "," .. b)
|
queueLines({ curUser .. " " .. cwd .. "> color",
|
||||||
|
"Color set to " .. r .. "," .. g .. "," .. b })
|
||||||
end, "Set color R G B")
|
end, "Set color R G B")
|
||||||
|
|
||||||
reg("status", function(a)
|
reg("status", function(a)
|
||||||
return "AtlasOS v2.0 | User: " .. curUser .. "(" .. uid .. ") | CWD: " .. cwd
|
pendingCmd = { name = "status",
|
||||||
|
prompt = curUser .. " " .. cwd .. "> status" }
|
||||||
|
state = ST_WAIT_FS
|
||||||
|
fsReq("STATFS", "")
|
||||||
end, "System status")
|
end, "System status")
|
||||||
|
|
||||||
reg("ls", function(a)
|
reg("ls", function(a)
|
||||||
@@ -87,39 +110,46 @@ reg("ls", function(a)
|
|||||||
if a[i]:sub(1, 1) == "-" then
|
if a[i]:sub(1, 1) == "-" then
|
||||||
opts[a[i]] = true
|
opts[a[i]] = true
|
||||||
else
|
else
|
||||||
path = a[i]
|
path = resolvePath(a[i])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
pendingCmd = { name = "ls", path = path, opts = opts }
|
local cmdStr = "ls"
|
||||||
|
if #a > 0 then cmdStr = "ls " .. table.concat(a, " ") end
|
||||||
|
pendingCmd = { name = "ls", opts = opts, path = path,
|
||||||
|
prompt = curUser .. " " .. cwd .. "> " .. cmdStr }
|
||||||
state = ST_WAIT_FS
|
state = ST_WAIT_FS
|
||||||
fsReq("LS", path)
|
fsReq("LS", path)
|
||||||
end, "List directory [path]")
|
end, "List directory [path]")
|
||||||
|
|
||||||
reg("cat", function(a)
|
reg("cat", function(a)
|
||||||
if #a == 0 then error("cat: missing path") end
|
if #a == 0 then error("cat: need path") end
|
||||||
pendingCmd = { name = "cat", path = a[1] }
|
local path = resolvePath(a[1])
|
||||||
|
pendingCmd = { name = "cat", path = path,
|
||||||
|
prompt = curUser .. " " .. cwd .. "> cat " .. a[1] }
|
||||||
state = ST_WAIT_FS
|
state = ST_WAIT_FS
|
||||||
fsReq("READ", a[1] .. "|0|8192")
|
fsReq("READ", path .. "|0|8192")
|
||||||
end, "Show file content")
|
end, "Show file content")
|
||||||
|
|
||||||
reg("cd", function(a)
|
reg("cd", function(a)
|
||||||
local path = a[1]
|
local path = a[1] and resolvePath(a[1]) or "/"
|
||||||
if not path then path = "/" end
|
pendingCmd = { name = "cd", path = path,
|
||||||
pendingCmd = { name = "cd", path = path }
|
prompt = curUser .. " " .. cwd .. "> cd " .. (a[1] or "") }
|
||||||
state = ST_WAIT_FS
|
state = ST_WAIT_FS
|
||||||
fsReq("CHDIR", path)
|
fsReq("CHDIR", path)
|
||||||
end, "Change directory [path]")
|
end, "Change directory [path]")
|
||||||
|
|
||||||
reg("stat", function(a)
|
reg("stat", function(a)
|
||||||
if #a == 0 then error("stat: missing path") end
|
if #a == 0 then error("stat: need path") end
|
||||||
pendingCmd = { name = "stat", path = a[1] }
|
local path = resolvePath(a[1])
|
||||||
|
pendingCmd = { name = "stat", path = path,
|
||||||
|
prompt = curUser .. " " .. cwd .. "> stat " .. a[1] }
|
||||||
state = ST_WAIT_FS
|
state = ST_WAIT_FS
|
||||||
fsReq("STAT", a[1])
|
fsReq("STAT", path)
|
||||||
end, "Show file metadata")
|
end, "Show file metadata")
|
||||||
|
|
||||||
local function execCmd(cmdStr)
|
local function execCmd(cmdStr)
|
||||||
local parts = {}
|
local parts = {}
|
||||||
for t in cmdStr:gmatch("%S+") do
|
for t in cmdStr:gmatch("[^ ]+") do
|
||||||
parts[#parts + 1] = t
|
parts[#parts + 1] = t
|
||||||
end
|
end
|
||||||
if #parts == 0 then return end
|
if #parts == 0 then return end
|
||||||
@@ -132,15 +162,15 @@ local function execCmd(cmdStr)
|
|||||||
|
|
||||||
local entry = cmds[name]
|
local entry = cmds[name]
|
||||||
if not entry then
|
if not entry then
|
||||||
printErr("Unknown: " .. name .. ". Try 'help'.")
|
qText(curUser .. " " .. cwd .. "> " .. cmdStr)
|
||||||
|
qErr("Unknown: " .. name .. ". Try 'help'.")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local ok, result = pcall(entry.fn, args)
|
local ok, msg = pcall(entry.fn, args)
|
||||||
if not ok then
|
if not ok then
|
||||||
printErr(tostring(result))
|
qText(curUser .. " " .. cwd .. "> " .. cmdStr)
|
||||||
elseif result ~= nil then
|
qErr(tostring(msg))
|
||||||
printOut(result)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -150,41 +180,64 @@ local function handleFSResponse(op, data)
|
|||||||
|
|
||||||
if op == "ERR" then
|
if op == "ERR" then
|
||||||
local code = data or "EIO"
|
local code = data or "EIO"
|
||||||
|
local m = cmd.path
|
||||||
if code == "ENOENT" then
|
if code == "ENOENT" then
|
||||||
printErr(cmd.path .. ": No such file or directory")
|
m = m .. ": No such file or directory"
|
||||||
elseif code == "EACCES" then
|
elseif code == "EACCES" then
|
||||||
printErr(cmd.path .. ": Permission denied")
|
m = m .. ": Permission denied"
|
||||||
elseif code == "ENOTDIR" then
|
elseif code == "ENOTDIR" then
|
||||||
printErr(cmd.path .. ": Not a directory")
|
m = m .. ": Not a directory"
|
||||||
elseif code == "EISDIR" then
|
elseif code == "EISDIR" then
|
||||||
printErr(cmd.path .. ": Is a directory")
|
m = m .. ": Is a directory"
|
||||||
else
|
else
|
||||||
printErr(cmd.path .. ": " .. code)
|
m = m .. ": " .. code
|
||||||
end
|
end
|
||||||
|
qText(cmd.prompt)
|
||||||
|
qErr(m)
|
||||||
pendingCmd = nil
|
pendingCmd = nil
|
||||||
state = ST_IDLE
|
state = ST_IDLE
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local lines = { cmd.prompt }
|
||||||
|
|
||||||
if cmd.name == "ls" then
|
if cmd.name == "ls" then
|
||||||
local showAll = (cmd.opts["-la"] or cmd.opts["-a"])
|
local showAll = (cmd.opts["-la"] or cmd.opts["-a"])
|
||||||
local names = {}
|
local names = {}
|
||||||
for n in data:gmatch("([^|]+)") do
|
for n in data:gmatch("([^|]+)") do
|
||||||
names[#names + 1] = n
|
names[#names + 1] = n
|
||||||
end
|
end
|
||||||
local outLines = {}
|
|
||||||
for _, n in ipairs(names) do
|
for _, n in ipairs(names) do
|
||||||
if n ~= "." and n ~= ".." or showAll then
|
if n ~= "." and n ~= ".." or showAll then
|
||||||
outLines[#outLines + 1] = n
|
lines[#lines + 1] = n
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if #outLines == 0 then outLines[1] = "(empty)" end
|
if #lines == 1 then lines[#lines + 1] = "(empty)" end
|
||||||
printOut(table.concat(outLines, "\n"))
|
|
||||||
elseif cmd.name == "cat" then
|
elseif cmd.name == "cat" then
|
||||||
printOut(data)
|
if data and #data > 0 then
|
||||||
|
for line in data:gmatch("[^\n]+") do
|
||||||
|
lines[#lines + 1] = line
|
||||||
|
end
|
||||||
|
else
|
||||||
|
lines[#lines + 1] = "(empty)"
|
||||||
|
end
|
||||||
|
|
||||||
elseif cmd.name == "cd" then
|
elseif cmd.name == "cd" then
|
||||||
cwd = data
|
cwd = data
|
||||||
printOut(cwd)
|
lines[#lines + 1] = cwd
|
||||||
|
|
||||||
|
elseif cmd.name == "status" then
|
||||||
|
local parts = {}
|
||||||
|
for s in data:gmatch("([^|]+)") do
|
||||||
|
parts[#parts + 1] = s
|
||||||
|
end
|
||||||
|
local total = tonumber(parts[1]) or 8192
|
||||||
|
local used = tonumber(parts[2]) or 0
|
||||||
|
lines[#lines + 1] = "AtlasOS v2.0 User: " .. curUser .. "(" .. uid .. ")"
|
||||||
|
lines[#lines + 1] = "CWD: " .. cwd
|
||||||
|
lines[#lines + 1] = "Mem: " .. (total - used) .. "/" .. total .. " free"
|
||||||
|
|
||||||
elseif cmd.name == "stat" then
|
elseif cmd.name == "stat" then
|
||||||
local parts = {}
|
local parts = {}
|
||||||
for s in data:gmatch("([^|]+)") do
|
for s in data:gmatch("([^|]+)") do
|
||||||
@@ -192,15 +245,15 @@ local function handleFSResponse(op, data)
|
|||||||
end
|
end
|
||||||
if #parts >= 6 then
|
if #parts >= 6 then
|
||||||
local typ = parts[2] == "d" and "directory" or "file"
|
local typ = parts[2] == "d" and "directory" or "file"
|
||||||
local out = "Inode: " .. parts[1] .. " Type: " .. typ .. "\n"
|
lines[#lines + 1] = "Inode: " .. parts[1] .. " Type: " .. typ
|
||||||
out = out .. "Mode: " .. parts[3] .. " UID: " .. parts[4] .. " GID: " .. parts[5] .. "\n"
|
lines[#lines + 1] = "Mode: " .. parts[3] .. " UID: " .. parts[4] .. " GID: " .. parts[5]
|
||||||
out = out .. "Size: " .. parts[6] .. " Modified: " .. (parts[7] or "?")
|
lines[#lines + 1] = "Size: " .. parts[6] .. " Modified: " .. (parts[7] or "?")
|
||||||
printOut(out)
|
|
||||||
else
|
else
|
||||||
printOut(data)
|
lines[#lines + 1] = data
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
queueLines(lines)
|
||||||
pendingCmd = nil
|
pendingCmd = nil
|
||||||
state = ST_IDLE
|
state = ST_IDLE
|
||||||
end
|
end
|
||||||
@@ -208,6 +261,18 @@ end
|
|||||||
inp = {}
|
inp = {}
|
||||||
|
|
||||||
function upd()
|
function upd()
|
||||||
|
if #outQueue > 0 then
|
||||||
|
local item = outQueue[1]
|
||||||
|
table.remove(outQueue, 1)
|
||||||
|
if item[1] == "t" then
|
||||||
|
out[1] = "OUT|" .. tostring(item[2])
|
||||||
|
elseif item[1] == "c" then
|
||||||
|
out[1] = "COL|" .. tostring(item[2])
|
||||||
|
elseif item[1] == "x" then
|
||||||
|
out[1] = "CLR"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if state == ST_IDLE then
|
if state == ST_IDLE then
|
||||||
if inp[1] ~= nil then
|
if inp[1] ~= nil then
|
||||||
local op, cmd = parseMsg(tostring(inp[1]))
|
local op, cmd = parseMsg(tostring(inp[1]))
|
||||||
|
|||||||
@@ -4,9 +4,7 @@
|
|||||||
-- out[3] = display_color → Terminal
|
-- out[3] = display_color → Terminal
|
||||||
-- out[4] = cmd_tx → CMC.in[1] (IN|command)
|
-- out[4] = cmd_tx → CMC.in[1] (IN|command)
|
||||||
-- in[1] = user_input ← Terminal
|
-- in[1] = user_input ← Terminal
|
||||||
-- in[2] = text_rx ← CMC.out[1] (OUT|text)
|
-- in[2] = cmd_rx ← CMC.out[1] (OUT|text / CLR / COL|R,G,B)
|
||||||
-- in[3] = clear_rx ← CMC.out[2] (1 = clear)
|
|
||||||
-- in[4] = color_rx ← CMC.out[3] (R,G,B)
|
|
||||||
|
|
||||||
local txActive = false
|
local txActive = false
|
||||||
|
|
||||||
@@ -23,16 +21,16 @@ function upd()
|
|||||||
|
|
||||||
if inp[2] ~= nil then
|
if inp[2] ~= nil then
|
||||||
local msg = tostring(inp[2])
|
local msg = tostring(inp[2])
|
||||||
local _, arg = msg:match("^(%w+)%|(.+)$")
|
local pipe = msg:find("|")
|
||||||
if arg then out[1] = arg end
|
local op = pipe and msg:sub(1, pipe - 1) or msg
|
||||||
end
|
local arg = pipe and msg:sub(pipe + 1) or nil
|
||||||
|
if op == "OUT" and arg then
|
||||||
if inp[3] ~= nil and tonumber(inp[3]) == 1 then
|
out[1] = arg
|
||||||
out[2] = 1
|
elseif op == "CLR" then
|
||||||
end
|
out[2] = 1
|
||||||
|
elseif op == "COL" and arg then
|
||||||
if inp[4] ~= nil then
|
out[3] = arg
|
||||||
out[3] = tostring(inp[4])
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
table.clear(inp)
|
table.clear(inp)
|
||||||
|
|||||||
@@ -178,6 +178,11 @@ local function processReq(req)
|
|||||||
end
|
end
|
||||||
return "OK|" .. seqStr .. table.concat(names, "|")
|
return "OK|" .. seqStr .. table.concat(names, "|")
|
||||||
|
|
||||||
|
elseif op == "STATFS" then
|
||||||
|
local total = sb.seg_size
|
||||||
|
local used = #fsSerialize()
|
||||||
|
return "OK|" .. seqStr .. total .. "|" .. used
|
||||||
|
|
||||||
elseif op == "CHDIR" then
|
elseif op == "CHDIR" then
|
||||||
local path = rest or "/"
|
local path = rest or "/"
|
||||||
local ino = findInodeByPath(path)
|
local ino = findInodeByPath(path)
|
||||||
|
|||||||
@@ -10,137 +10,131 @@
|
|||||||
| Terminal | 1 | текстовый дисплей |
|
| Terminal | 1 | текстовый дисплей |
|
||||||
| Memory | 1 | хранилище 8192 символа |
|
| Memory | 1 | хранилище 8192 символа |
|
||||||
|
|
||||||
## Полная схема
|
## Распиновка и соединения
|
||||||
|
|
||||||
|
### IOC — I/O Controller
|
||||||
|
|
||||||
```
|
```
|
||||||
Терминал (Keyboard/Button) Терминал (Display)
|
in[1] ← Terminal (текстовый ввод)
|
||||||
│ text ▲
|
in[2] ← CMC.out[1] (текст "OUT|...")
|
||||||
▼ │ text
|
in[3] ← CMC.out[2] (очистка, 1)
|
||||||
┌──────────┐ ┌──────────┐ │ clear
|
in[4] ← CMC.out[3] (цвет "R,G,B")
|
||||||
│ │─────────▶ │──────┤ color
|
out[1] → Terminal (текст на экран)
|
||||||
│ IOC │ IN|cmd │ CMC │ │
|
out[2] → Terminal (очистка)
|
||||||
│ │◀────────│ │◀─────┤
|
out[3] → Terminal (цвет "R,G,B")
|
||||||
└──────────┘ OUT|text│ │ 1 │
|
out[4] → CMC.in[1] (команда "IN|...")
|
||||||
▲ clear=1 │ │◀─────┤
|
|
||||||
│ R,G,B └────▲────┘ R,G,B│
|
|
||||||
│ │ │
|
|
||||||
│ LS|path │
|
|
||||||
│ READ|... │
|
|
||||||
│ │ │
|
|
||||||
│ ┌────▼────┐ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ MMC │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ └──┬──┬───┘ │
|
|
||||||
│ │ │ │
|
|
||||||
│ data │ │ write(1) │
|
|
||||||
│ ▼ ▼ │
|
|
||||||
│ ┌────────┐ │
|
|
||||||
│ │ Memory │ │
|
|
||||||
│ │ 8192 │ │
|
|
||||||
│ └───┬────┘ │
|
|
||||||
│ │ │
|
|
||||||
└──────────────────┴────────────┘
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Соединения проводом
|
### CMC — Command Controller
|
||||||
|
|
||||||
### IOC ↔ Терминал
|
```
|
||||||
|
in[1] ← IOC.out[4] (команда "IN|...")
|
||||||
|
in[2] ← MMC.out[1] (ответ ФС "OK|seq|..." / "ERR|seq|...")
|
||||||
|
out[1] → IOC.in[2] (текст "OUT|...")
|
||||||
|
out[2] → IOC.in[3] (очистка, 1)
|
||||||
|
out[3] → IOC.in[4] (цвет "R,G,B")
|
||||||
|
out[4] → MMC.in[1] (запрос ФС "OP|...")
|
||||||
|
```
|
||||||
|
|
||||||
| Пин IOC | → / ← | Пин Terminal | Назначение |
|
### MMC — Memory/FS Controller
|
||||||
|---|---|---|---|
|
|
||||||
| IOC.out[1] | → | Display.in (text) | текст на экран |
|
|
||||||
| IOC.out[2] | → | Display.in (clear) | очистка (1) |
|
|
||||||
| IOC.out[3] | → | Display.in (color) | цвет R,G,B |
|
|
||||||
| IOC.in[1] | ← | Keyboard.out (text) | ввод пользователя |
|
|
||||||
|
|
||||||
### IOC ↔ CMC
|
```
|
||||||
|
in[1] ← CMC.out[4] (запрос ФС "OP|...")
|
||||||
|
in[3] ← Memory.out[1] (чтение данных)
|
||||||
|
out[1] → CMC.in[2] (ответ ФС "OK|seq|..." / "ERR|seq|...")
|
||||||
|
out[5] → Memory.in[1] (запись данных)
|
||||||
|
out[6] → Memory.in[2] (сигнал записи, 1)
|
||||||
|
```
|
||||||
|
|
||||||
| Пин IOC | → / ← | Пин CMC | Назначение |
|
### Memory
|
||||||
|---|---|---|---|
|
|
||||||
| IOC.out[4] | → | CMC.in[1] | команда `IN|cmd` |
|
|
||||||
| CMC.out[1] | → | IOC.in[2] | текст `OUT|text` |
|
|
||||||
| CMC.out[2] | → | IOC.in[3] | очистка (1) |
|
|
||||||
| CMC.out[3] | → | IOC.in[4] | цвет `R,G,B` |
|
|
||||||
|
|
||||||
### CMC ↔ MMC
|
```
|
||||||
|
in[1] ← MMC.out[5] (данные для записи)
|
||||||
|
in[2] ← MMC.out[6] (сигнал записи, 1)
|
||||||
|
out[1] → MMC.in[3] (хранимое значение)
|
||||||
|
```
|
||||||
|
|
||||||
| Пин CMC | → / ← | Пин MMC | Назначение |
|
## Формат вывода терминала
|
||||||
|---|---|---|---|
|
|
||||||
| CMC.out[4] | → | MMC.in[1] | запрос `OP|args` |
|
|
||||||
| MMC.out[1] | → | CMC.in[2] | ответ `OK|seq|...` |
|
|
||||||
|
|
||||||
### MMC ↔ Memory
|
Терминал: 72 символа × 17 строк.
|
||||||
|
|
||||||
| Пин MMC | → / ← | Пин Memory | Назначение |
|
Вывод строится очередью — одна строка за кадр. Приглашение ввода:
|
||||||
|---|---|---|---|
|
|
||||||
| MMC.out[5] | → | Memory.in[1] | данные для записи |
|
```
|
||||||
| MMC.out[6] | → | Memory.in[2] | сигнал записи (1) |
|
root /path$ команда_пользователя
|
||||||
| Memory.out[1] | → | MMC.in[3] | чтение данных |
|
<результат команды>
|
||||||
|
```
|
||||||
|
|
||||||
|
Ошибки отображаются красным цветом. Свободная память — `status`.
|
||||||
|
|
||||||
## Протокол шины
|
## Протокол шины
|
||||||
|
|
||||||
### IOC → CMC (CMD)
|
### IOC → CMC (CMD)
|
||||||
|
|
||||||
```
|
```
|
||||||
IN|команда
|
IN|команда_и_аргументы
|
||||||
```
|
```
|
||||||
|
|
||||||
### CMC → IOC (CMD)
|
Пример: `IN|ls /home`, `IN|cat readme.txt`
|
||||||
|
|
||||||
```
|
### CMC → IOC (три отдельных пина)
|
||||||
OUT|текст — вывести текст
|
|
||||||
1 на out[2] — очистить экран
|
|
||||||
R,G,B на out[3] — установить цвет
|
|
||||||
```
|
|
||||||
|
|
||||||
### CMC → MMC (MEM)
|
out[1] — текст: `OUT|текст`
|
||||||
|
out[2] — очистка: `1`
|
||||||
|
out[3] — цвет: `R,G,B`
|
||||||
|
|
||||||
```
|
Контроллер IOC разбирает эти три пина независимо.
|
||||||
STAT|путь — метаданные
|
|
||||||
READ|путь|смещение|длина — чтение файла
|
|
||||||
LS|путь — список каталога
|
|
||||||
CHDIR|путь — смена директории (проверка)
|
|
||||||
WRITE|путь|смещение|данные — запись (пока EROFS)
|
|
||||||
```
|
|
||||||
|
|
||||||
### MMC → CMC (MEM)
|
### CMC → MMC (MEM — запросы)
|
||||||
|
|
||||||
```
|
| Опкод | Формат | Описание |
|
||||||
OK|seq|данные
|
|---|---|---|
|
||||||
ERR|seq|код_ошибки
|
| `LS` | `LS|путь` | список каталога |
|
||||||
```
|
| `READ` | `READ|путь|смещение|длина` | чтение файла |
|
||||||
|
| `STAT` | `STAT|путь` | метаданные inode |
|
||||||
|
| `CHDIR` | `CHDIR|путь` | смена рабочего каталога (проверка `x`) |
|
||||||
|
| `STATFS` | `STATFS` | статистика памяти: `total\|used` |
|
||||||
|
| `WRITE` | `WRITE|путь|...` | запись (пока readonly — EROFS) |
|
||||||
|
|
||||||
Коды ошибок: `ENOENT`, `EACCES`, `ENOTDIR`, `EISDIR`, `EROFS`, `EINVAL`
|
### MMC → CMC (MEM — ответы)
|
||||||
|
|
||||||
|
Успех: `OK|seq|данные`
|
||||||
|
Ошибка: `ERR|seq|код`
|
||||||
|
|
||||||
|
Коды: `ENOENT`, `EACCES`, `ENOTDIR`, `EISDIR`, `EROFS`, `EINVAL`
|
||||||
|
|
||||||
|
Поле `seq` — монотонный счётчик (позволяет CMC отличить новый ответ от старого).
|
||||||
|
|
||||||
|
## Команды CMC
|
||||||
|
|
||||||
|
| Команда | Аргументы | Описание |
|
||||||
|
|---|---|---|
|
||||||
|
| `help` | — | список команд |
|
||||||
|
| `echo` | текст | вывести текст |
|
||||||
|
| `clear` | — | очистить экран |
|
||||||
|
| `color` | R G B | установить цвет (0-255) |
|
||||||
|
| `status` | — | система + свободная память |
|
||||||
|
| `ls` | `[-a] [путь]` | список файлов; `-a` включая `.` и `..` |
|
||||||
|
| `cat` | путь | содержимое файла |
|
||||||
|
| `cd` | `[путь]` | сменить каталог; без аргумента → `/` |
|
||||||
|
| `stat` | путь | метаданные файла/каталога |
|
||||||
|
|
||||||
|
Пути могут быть абсолютные (`/home/file.txt`) или относительные (`file.txt` — относительно `cwd`).
|
||||||
|
|
||||||
## Последовательность запуска
|
## Последовательность запуска
|
||||||
|
|
||||||
1. Загрузить код MMC.lua в контроллер MMC
|
1. Загрузить код **MMC.lua** → старт, чтение Memory; если пусто — инициализация ФС по умолчанию
|
||||||
2. Загрузить код CMC.lua в контроллер CMC
|
2. Загрузить код **CMC.lua** → старт, ожидание команд
|
||||||
3. Загрузить код IOC.lua в контроллер IOC
|
3. Загрузить код **IOC.lua** → старт, ожидание ввода
|
||||||
4. Соединить провода по схеме выше
|
4. Соединить провода по схеме
|
||||||
5. При первом запуске MMC инициализирует пустую ФС и запишет в Memory
|
5. Ввод с клавиатуры → отобразится приглашение `root />`
|
||||||
6. Подать сигнал на Terminal — появится приглашение
|
|
||||||
|
|
||||||
## Пример сессии
|
## Пример сессии
|
||||||
|
|
||||||
```
|
```
|
||||||
> ls
|
root /> help
|
||||||
home
|
AtlasOS v2.0:
|
||||||
etc
|
help This help
|
||||||
> ls /home/captain
|
|
||||||
readme.txt
|
|
||||||
> cat /home/captain/readme.txt
|
|
||||||
Welcome to AtlasOS v2.0!
|
|
||||||
> cd /home/captain
|
|
||||||
/home/captain
|
|
||||||
> status
|
|
||||||
AtlasOS v2.0 | User: root(0) | CWD: /home/captain
|
|
||||||
> color 0 255 128
|
|
||||||
Color set to 0,255,128
|
|
||||||
> help
|
|
||||||
AtlasOS v2.0 commands:
|
|
||||||
help Show help
|
|
||||||
echo Echo text
|
echo Echo text
|
||||||
clear Clear screen
|
clear Clear screen
|
||||||
color Set color R G B
|
color Set color R G B
|
||||||
@@ -149,4 +143,20 @@ AtlasOS v2.0 commands:
|
|||||||
cat Show file content
|
cat Show file content
|
||||||
cd Change directory [path]
|
cd Change directory [path]
|
||||||
stat Show file metadata
|
stat Show file metadata
|
||||||
|
root /> status
|
||||||
|
AtlasOS v2.0 User: root(0)
|
||||||
|
CWD: /
|
||||||
|
Mem: 7900/8192 free
|
||||||
|
root /> cat /home/captain/readme.txt
|
||||||
|
Welcome to AtlasOS v2.0!
|
||||||
|
root /> cd /home/captain
|
||||||
|
/home/captain
|
||||||
|
root /home/captain$ ls
|
||||||
|
readme.txt
|
||||||
|
root /home/captain$ color 0 255 128
|
||||||
|
Color set to 0,255,128
|
||||||
|
root /home/captain$ cat nonexistent
|
||||||
|
nonexistent: No such file or directory (красным)
|
||||||
|
root /> unknown
|
||||||
|
Unknown: unknown. Try 'help'. (красным)
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user