mirror of
https://github.com/paradoxxxzero/butterfly.git
synced 2026-05-26 07:08:08 +00:00
Implement 16M colors
This commit is contained in:
8
bin/16Mtest
Executable file
8
bin/16Mtest
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/env python
|
||||
import sys
|
||||
import os
|
||||
rows, cols = map(int, os.popen('stty size', 'r').read().split())
|
||||
|
||||
for r in range(rows):
|
||||
for c in range(cols):
|
||||
sys.stdout.write('\x1b[48;2;%d;%d;%dm ' % (255 - r, 255 - c, 255))
|
||||
@@ -205,6 +205,34 @@
|
||||
setTimeout(this.resize.bind(this), 100);
|
||||
}
|
||||
|
||||
Terminal.prototype.getDefAttr = function() {
|
||||
return {
|
||||
bg: 256,
|
||||
fg: 0,
|
||||
bold: false,
|
||||
underline: false,
|
||||
blink: false,
|
||||
inverse: false,
|
||||
invisible: false
|
||||
};
|
||||
};
|
||||
|
||||
Terminal.prototype.cloneAttr = function(a) {
|
||||
return {
|
||||
bg: a.bg,
|
||||
fg: a.fg,
|
||||
bold: a.bold,
|
||||
underline: a.underline,
|
||||
blink: a.blink,
|
||||
inverse: a.inverse,
|
||||
invisible: a.invisible
|
||||
};
|
||||
};
|
||||
|
||||
Terminal.prototype.equalAttr = function(a, b) {
|
||||
return a.bg === b.bg && a.fg === b.fg && a.bold === b.bold && a.underline === b.underline && a.blink === b.blink && a.inverse === b.inverse && a.invisible === b.invisible;
|
||||
};
|
||||
|
||||
Terminal.prototype.reset_vars = function() {
|
||||
var i;
|
||||
this.x = 0;
|
||||
@@ -225,8 +253,8 @@
|
||||
this.gcharset = null;
|
||||
this.glevel = 0;
|
||||
this.charsets = [null];
|
||||
this.defAttr = (0 << 18) | (257 << 9) | (256 << 0);
|
||||
this.curAttr = this.defAttr;
|
||||
this.defAttr = this.getDefAttr();
|
||||
this.curAttr = this.getDefAttr();
|
||||
this.params = [];
|
||||
this.currentParam = 0;
|
||||
this.prefix = "";
|
||||
@@ -458,7 +486,7 @@
|
||||
};
|
||||
|
||||
Terminal.prototype.refresh = function(start, end) {
|
||||
var attr, bg, ch, classes, data, fg, flags, html, i, j, k, l, line, m, out, parent, ref, ref1, ref2, ref3, row, x;
|
||||
var attr, ch, classes, data, fg, html, i, j, k, l, line, m, out, parent, ref, ref1, ref2, ref3, row, styles, x;
|
||||
if (!this.native_scroll && end - start >= this.rows / 3) {
|
||||
parent = this.element.parentNode;
|
||||
if (parent != null) {
|
||||
@@ -475,43 +503,56 @@
|
||||
} else {
|
||||
x = -Infinity;
|
||||
}
|
||||
attr = this.defAttr;
|
||||
attr = this.getDefAttr();
|
||||
for (i = m = 0, ref2 = this.cols - 1; 0 <= ref2 ? m <= ref2 : m >= ref2; i = 0 <= ref2 ? ++m : --m) {
|
||||
data = line[i][0];
|
||||
ch = line[i][1];
|
||||
if (data !== attr) {
|
||||
if (attr !== this.defAttr) {
|
||||
if (!this.equalAttr(data, attr)) {
|
||||
if (!this.equalAttr(attr, this.getDefAttr())) {
|
||||
out += "</span>";
|
||||
}
|
||||
if (data !== this.defAttr) {
|
||||
if (!this.equalAttr(data, this.getDefAttr())) {
|
||||
classes = [];
|
||||
styles = [];
|
||||
out += "<span ";
|
||||
bg = data & 0x1ff;
|
||||
fg = (data >> 9) & 0x1ff;
|
||||
flags = data >> 18;
|
||||
if (flags & 1) {
|
||||
if (data.bold) {
|
||||
classes.push("bold");
|
||||
}
|
||||
if (flags & 2) {
|
||||
if (data.underline) {
|
||||
classes.push("underline");
|
||||
}
|
||||
if (flags & 4) {
|
||||
if (data.blink) {
|
||||
classes.push("blink");
|
||||
}
|
||||
if (flags & 8) {
|
||||
if (data.inverse) {
|
||||
classes.push("reverse-video");
|
||||
}
|
||||
if (flags & 16) {
|
||||
if (data.invisible) {
|
||||
classes.push("invisible");
|
||||
}
|
||||
if (flags & 1 && fg < 8) {
|
||||
fg += 8;
|
||||
if (typeof data.fg === 'number') {
|
||||
fg = data.fg;
|
||||
if (data.bold && fg < 8) {
|
||||
fg += 8;
|
||||
}
|
||||
classes.push("fg-color-" + fg);
|
||||
}
|
||||
if (typeof data.fg === 'string') {
|
||||
styles.push("color: " + data.fg);
|
||||
}
|
||||
if (typeof data.bg === 'number') {
|
||||
classes.push("bg-color-" + data.bg);
|
||||
}
|
||||
if (typeof data.bg === 'string') {
|
||||
styles.push("background-color: " + data.bg);
|
||||
}
|
||||
classes.push("bg-color-" + bg);
|
||||
classes.push("fg-color-" + fg);
|
||||
out += "class=\"";
|
||||
out += classes.join(" ");
|
||||
out += "\">";
|
||||
out += "\"";
|
||||
if (styles.length) {
|
||||
out += " style=\"" + styles.join("; ") + "\"";
|
||||
}
|
||||
out += ">";
|
||||
}
|
||||
}
|
||||
if (i === x) {
|
||||
@@ -548,7 +589,7 @@
|
||||
}
|
||||
attr = data;
|
||||
}
|
||||
if (attr !== this.defAttr) {
|
||||
if (!this.equalAttr(attr, this.getDefAttr())) {
|
||||
out += "</span>";
|
||||
}
|
||||
this.children[j].innerHTML = out;
|
||||
@@ -747,19 +788,19 @@
|
||||
ch = this.charset[ch];
|
||||
}
|
||||
if (this.x >= this.cols) {
|
||||
this.screen[this.y + this.ybase][this.x] = [this.curAttr, '\u23CE'];
|
||||
this.screen[this.y + this.ybase][this.x] = [this.cloneAttr(this.curAttr), '\u23CE'];
|
||||
this.x = 0;
|
||||
this.next_line();
|
||||
}
|
||||
this.updateRange(this.y);
|
||||
this.screen[this.y + this.ybase][this.x] = [this.curAttr, ch];
|
||||
this.screen[this.y + this.ybase][this.x] = [this.cloneAttr(this.curAttr), ch];
|
||||
this.x++;
|
||||
if (("\uff00" < ch && ch < "\uffef")) {
|
||||
if (this.cols < 2 || this.x >= this.cols) {
|
||||
this.screen[this.y + this.ybase][this.x - 1] = [this.curAttr, " "];
|
||||
this.screen[this.y + this.ybase][this.x - 1] = [this.cloneAttr(this.curAttr), " "];
|
||||
break;
|
||||
}
|
||||
this.screen[this.y + this.ybase][this.x] = [this.curAttr, " "];
|
||||
this.screen[this.y + this.ybase][this.x] = [this.cloneAttr(this.curAttr), " "];
|
||||
this.x++;
|
||||
}
|
||||
}
|
||||
@@ -1133,7 +1174,7 @@
|
||||
this.updateRange(this.y);
|
||||
} else {
|
||||
html = "<div class=\"inline-html\">" + content + "</div>";
|
||||
this.screen[this.y + this.ybase][this.x] = [this.curAttr, html];
|
||||
this.screen[this.y + this.ybase][this.x] = [this.cloneAttr(this.curAttr), html];
|
||||
line = 0;
|
||||
while (line < this.get_html_height_in_lines(html) - 1) {
|
||||
this.y++;
|
||||
@@ -1895,85 +1936,81 @@
|
||||
};
|
||||
|
||||
Terminal.prototype.charAttributes = function(params) {
|
||||
var bg, fg, flags, i, l, p;
|
||||
var i, l, p, results;
|
||||
if (params.length === 1 && params[0] === 0) {
|
||||
this.curAttr = this.defAttr;
|
||||
this.curAttr = this.getDefAttr();
|
||||
return;
|
||||
}
|
||||
flags = this.curAttr >> 18;
|
||||
fg = (this.curAttr >> 9) & 0x1ff;
|
||||
bg = this.curAttr & 0x1ff;
|
||||
l = params.length;
|
||||
i = 0;
|
||||
results = [];
|
||||
while (i < l) {
|
||||
p = params[i];
|
||||
if (p >= 30 && p <= 37) {
|
||||
fg = p - 30;
|
||||
this.curAttr.fg = p - 30;
|
||||
} else if (p >= 40 && p <= 47) {
|
||||
bg = p - 40;
|
||||
this.curAttr.bg = p - 40;
|
||||
} else if (p >= 90 && p <= 97) {
|
||||
p += 8;
|
||||
fg = p - 90;
|
||||
this.curAttr.fg = p - 90;
|
||||
} else if (p >= 100 && p <= 107) {
|
||||
p += 8;
|
||||
bg = p - 100;
|
||||
this.curAttr.bg = p - 100;
|
||||
} else if (p === 0) {
|
||||
flags = this.defAttr >> 18;
|
||||
fg = (this.defAttr >> 9) & 0x1ff;
|
||||
bg = this.defAttr & 0x1ff;
|
||||
this.curAttr = this.getDefAttr();
|
||||
} else if (p === 1) {
|
||||
flags |= 1;
|
||||
this.curAttr.bold = true;
|
||||
} else if (p === 4) {
|
||||
flags |= 2;
|
||||
this.curAttr.underline = true;
|
||||
} else if (p === 5) {
|
||||
flags |= 4;
|
||||
this.curAttr.blink = true;
|
||||
} else if (p === 7) {
|
||||
flags |= 8;
|
||||
this.curAttr.inverse = true;
|
||||
} else if (p === 8) {
|
||||
flags |= 16;
|
||||
this.curAttr.invisible = true;
|
||||
} else if (p === 10) {
|
||||
|
||||
} else if (p === 22) {
|
||||
flags &= ~1;
|
||||
this.curAttr.bold = false;
|
||||
} else if (p === 24) {
|
||||
flags &= ~2;
|
||||
this.curAttr.underline = false;
|
||||
} else if (p === 25) {
|
||||
flags &= ~4;
|
||||
this.curAttr.blink = false;
|
||||
} else if (p === 27) {
|
||||
flags &= ~8;
|
||||
this.curAttr.inverse = false;
|
||||
} else if (p === 28) {
|
||||
flags &= ~16;
|
||||
this.curAttr.invisible = false;
|
||||
} else if (p === 39) {
|
||||
fg = (this.defAttr >> 9) & 0x1ff;
|
||||
this.curAttr.fg = 0;
|
||||
} else if (p === 49) {
|
||||
bg = this.defAttr & 0x1ff;
|
||||
this.curAttr.bg = 256;
|
||||
} else if (p === 38) {
|
||||
if (params[i + 1] === 2) {
|
||||
i += 2;
|
||||
fg = "#" + params[i] & 0xff + params[i + 1] & 0xff + params[i + 2] & 0xff;
|
||||
this.curAttr.fg = "rgb(" + params[i] + ", " + params[i + 1] + ", " + params[i + 2] + ")";
|
||||
i += 2;
|
||||
} else if (params[i + 1] === 5) {
|
||||
i += 2;
|
||||
fg = params[i] & 0xff;
|
||||
this.curAttr.fg = params[i] & 0xff;
|
||||
}
|
||||
} else if (p === 48) {
|
||||
if (params[i + 1] === 2) {
|
||||
i += 2;
|
||||
bg = "#" + params[i] & 0xff + params[i + 1] & 0xff + params[i + 2] & 0xff;
|
||||
this.curAttr.bg = "rgb(" + params[i] + ", " + params[i + 1] + ", " + params[i + 2] + ")";
|
||||
i += 2;
|
||||
} else if (params[i + 1] === 5) {
|
||||
i += 2;
|
||||
bg = params[i] & 0xff;
|
||||
this.curAttr.bg = params[i] & 0xff;
|
||||
}
|
||||
} else if (p === 100) {
|
||||
fg = (this.defAttr >> 9) & 0x1ff;
|
||||
bg = this.defAttr & 0x1ff;
|
||||
this.curAttr.fg = 0;
|
||||
this.curAttr.bg = 256;
|
||||
} else {
|
||||
console.error("Unknown SGR attribute: %d.", p);
|
||||
}
|
||||
i++;
|
||||
results.push(i++);
|
||||
}
|
||||
return this.curAttr = (flags << 18) | (fg << 9) | bg;
|
||||
return results;
|
||||
};
|
||||
|
||||
Terminal.prototype.deviceStatus = function(params) {
|
||||
|
||||
@@ -118,6 +118,29 @@ class Terminal
|
||||
|
||||
setTimeout(@resize.bind(@), 100)
|
||||
|
||||
getDefAttr: ->
|
||||
bg: 256
|
||||
fg: 0
|
||||
bold: false
|
||||
underline: false
|
||||
blink: false
|
||||
inverse: false
|
||||
invisible: false
|
||||
|
||||
cloneAttr: (a) ->
|
||||
bg: a.bg
|
||||
fg: a.fg
|
||||
bold: a.bold
|
||||
underline: a.underline
|
||||
blink: a.blink
|
||||
inverse: a.inverse
|
||||
invisible: a.invisible
|
||||
|
||||
equalAttr: (a, b) ->
|
||||
(a.bg is b.bg and a.fg is b.fg and a.bold is b.bold and
|
||||
a.underline is b.underline and a.blink is b.blink and
|
||||
a.inverse is b.inverse and a.invisible is b.invisible)
|
||||
|
||||
reset_vars: ->
|
||||
@x = 0
|
||||
@y = 0
|
||||
@@ -144,8 +167,9 @@ class Terminal
|
||||
@charsets = [null]
|
||||
|
||||
# stream
|
||||
@defAttr = (0 << 18) | (257 << 9) | (256 << 0)
|
||||
@curAttr = @defAttr
|
||||
@defAttr = @getDefAttr()
|
||||
|
||||
@curAttr = @getDefAttr()
|
||||
@params = []
|
||||
@currentParam = 0
|
||||
@prefix = ""
|
||||
@@ -397,37 +421,50 @@ class Terminal
|
||||
else
|
||||
x = -Infinity
|
||||
|
||||
attr = @defAttr
|
||||
attr = @getDefAttr()
|
||||
for i in [0..@cols - 1]
|
||||
data = line[i][0]
|
||||
ch = line[i][1]
|
||||
if data isnt attr
|
||||
out += "</span>" if attr isnt @defAttr
|
||||
if data isnt @defAttr
|
||||
unless @equalAttr data, attr
|
||||
out += "</span>" unless @equalAttr attr, @getDefAttr()
|
||||
unless @equalAttr data, @getDefAttr()
|
||||
classes = []
|
||||
styles = []
|
||||
out += "<span "
|
||||
bg = data & 0x1ff
|
||||
fg = (data >> 9) & 0x1ff
|
||||
flags = data >> 18
|
||||
|
||||
# bold
|
||||
classes.push "bold" if flags & 1
|
||||
classes.push "bold" if data.bold
|
||||
# underline
|
||||
classes.push "underline" if flags & 2
|
||||
classes.push "underline" if data.underline
|
||||
# blink
|
||||
classes.push "blink" if flags & 4
|
||||
classes.push "blink" if data.blink
|
||||
# inverse
|
||||
classes.push "reverse-video" if flags & 8
|
||||
classes.push "reverse-video" if data.inverse
|
||||
# invisible
|
||||
classes.push "invisible" if flags & 16
|
||||
classes.push "invisible" if data.invisible
|
||||
|
||||
fg += 8 if flags & 1 and fg < 8
|
||||
classes.push "bg-color-" + bg
|
||||
classes.push "fg-color-" + fg
|
||||
if typeof data.fg is 'number'
|
||||
fg = data.fg
|
||||
if data.bold and fg < 8
|
||||
fg += 8
|
||||
classes.push "fg-color-" + fg
|
||||
|
||||
if typeof data.fg is 'string'
|
||||
styles.push "color: " + data.fg
|
||||
|
||||
if typeof data.bg is 'number'
|
||||
classes.push "bg-color-" + data.bg
|
||||
|
||||
if typeof data.bg is 'string'
|
||||
styles.push "background-color: " + data.bg
|
||||
|
||||
out += "class=\""
|
||||
out += classes.join(" ")
|
||||
out += "\">"
|
||||
out += "\""
|
||||
if styles.length
|
||||
out += " style=\"" + styles.join("; ") + "\""
|
||||
out += ">"
|
||||
|
||||
out += "<span class=\"" + (
|
||||
if @cursorState then "reverse-video " else ""
|
||||
) + "cursor\">" if i is x
|
||||
@@ -453,7 +490,7 @@ class Terminal
|
||||
out += ch
|
||||
out += "</span>" if i is x
|
||||
attr = data
|
||||
out += "</span>" if attr isnt @defAttr
|
||||
out += "</span>" unless @equalAttr attr, @getDefAttr()
|
||||
@children[j].innerHTML = out
|
||||
parent?.appendChild @element
|
||||
|
||||
@@ -625,20 +662,20 @@ class Terminal
|
||||
if ch >= " "
|
||||
ch = @charset[ch] if @charset?[ch]
|
||||
if @x >= @cols
|
||||
@screen[@y + @ybase][@x] = [@curAttr, '\u23CE']
|
||||
@screen[@y + @ybase][@x] = [@cloneAttr(@curAttr), '\u23CE']
|
||||
@x = 0
|
||||
@next_line()
|
||||
|
||||
@updateRange @y
|
||||
|
||||
@screen[@y + @ybase][@x] = [@curAttr, ch]
|
||||
@screen[@y + @ybase][@x] = [@cloneAttr(@curAttr), ch]
|
||||
@x++
|
||||
if "\uff00" < ch < "\uffef"
|
||||
if @cols < 2 or @x >= @cols
|
||||
@screen[@y + @ybase][@x - 1] = [@curAttr, " "]
|
||||
@screen[@y + @ybase][@x - 1] = [@cloneAttr(@curAttr), " "]
|
||||
break
|
||||
|
||||
@screen[@y + @ybase][@x] = [@curAttr, " "]
|
||||
@screen[@y + @ybase][@x] = [@cloneAttr(@curAttr), " "]
|
||||
@x++
|
||||
|
||||
when State.escaped
|
||||
@@ -1079,7 +1116,7 @@ class Terminal
|
||||
else
|
||||
html = "<div class=\"inline-html\">" + content + "</div>"
|
||||
@screen[@y + @ybase][@x] = [
|
||||
@curAttr
|
||||
@cloneAttr(@curAttr)
|
||||
html
|
||||
]
|
||||
line = 0
|
||||
@@ -1778,7 +1815,7 @@ class Terminal
|
||||
# Ps = 7 -> Inverse.
|
||||
# Ps = 8 -> Invisible, i.e., hidden (VT300).
|
||||
# Ps = 2 2 -> Normal (neither bold nor faint).
|
||||
# Ps = 2 4 -> Not underlined.
|
||||
# Ps = 2 4 -> Not underline.
|
||||
# Ps = 2 5 -> Steady (not blinking).
|
||||
# Ps = 2 7 -> Positive (not inverse).
|
||||
# Ps = 2 8 -> Visible, i.e., not hidden (VT300).
|
||||
@@ -1835,113 +1872,96 @@ class Terminal
|
||||
charAttributes: (params) ->
|
||||
# Optimize a single SGR0.
|
||||
if params.length is 1 and params[0] is 0
|
||||
@curAttr = @defAttr
|
||||
@curAttr = @getDefAttr()
|
||||
return
|
||||
flags = @curAttr >> 18
|
||||
|
||||
fg = (@curAttr >> 9) & 0x1ff
|
||||
bg = @curAttr & 0x1ff
|
||||
|
||||
l = params.length
|
||||
i = 0
|
||||
while i < l
|
||||
p = params[i]
|
||||
if p >= 30 and p <= 37
|
||||
# fg color 8
|
||||
fg = p - 30
|
||||
@curAttr.fg = p - 30
|
||||
else if p >= 40 and p <= 47
|
||||
# bg color 8
|
||||
bg = p - 40
|
||||
@curAttr.bg = p - 40
|
||||
else if p >= 90 and p <= 97
|
||||
# fg color 16
|
||||
p += 8
|
||||
fg = p - 90
|
||||
@curAttr.fg = p - 90
|
||||
else if p >= 100 and p <= 107
|
||||
# bg color 16
|
||||
p += 8
|
||||
bg = p - 100
|
||||
@curAttr.bg = p - 100
|
||||
else if p is 0
|
||||
# default
|
||||
flags = @defAttr >> 18
|
||||
fg = (@defAttr >> 9) & 0x1ff
|
||||
bg = @defAttr & 0x1ff
|
||||
|
||||
# flags = 0;
|
||||
# fg = 0x1ff;
|
||||
# bg = 0x1ff;
|
||||
@curAttr = @getDefAttr()
|
||||
else if p is 1
|
||||
# bold text
|
||||
flags |= 1
|
||||
@curAttr.bold = true
|
||||
else if p is 4
|
||||
# underlined text
|
||||
flags |= 2
|
||||
# underline text
|
||||
@curAttr.underline = true
|
||||
else if p is 5
|
||||
# blink
|
||||
flags |= 4
|
||||
@curAttr.blink = true
|
||||
else if p is 7
|
||||
# inverse and positive
|
||||
# test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m'
|
||||
flags |= 8
|
||||
@curAttr.inverse = true
|
||||
else if p is 8
|
||||
# invisible
|
||||
flags |= 16
|
||||
@curAttr.invisible = true
|
||||
else if p is 10
|
||||
# Primary Font
|
||||
# ignoring
|
||||
else if p is 22
|
||||
# not bold
|
||||
flags &= ~1
|
||||
@curAttr.bold = false
|
||||
else if p is 24
|
||||
# not underlined
|
||||
flags &= ~2
|
||||
# not underline
|
||||
@curAttr.underline = false
|
||||
else if p is 25
|
||||
# not blink
|
||||
flags &= ~4
|
||||
@curAttr.blink = false
|
||||
else if p is 27
|
||||
# not inverse
|
||||
flags &= ~8
|
||||
@curAttr.inverse = false
|
||||
else if p is 28
|
||||
# not invisible
|
||||
flags &= ~16
|
||||
@curAttr.invisible = false
|
||||
else if p is 39
|
||||
# reset fg
|
||||
fg = (@defAttr >> 9) & 0x1ff
|
||||
@curAttr.fg = 0
|
||||
else if p is 49
|
||||
# reset bg
|
||||
bg = @defAttr & 0x1ff
|
||||
@curAttr.bg = 256
|
||||
else if p is 38
|
||||
if params[i + 1] is 2
|
||||
# fg color 2^24
|
||||
i += 2
|
||||
fg = "#" + params[i] & 0xff +
|
||||
params[i + 1] & 0xff +
|
||||
params[i + 2] & 0xff
|
||||
@curAttr.fg = "rgb(#{params[i]}, #{params[i+1]}, #{params[i+2]})"
|
||||
i += 2
|
||||
else if params[i + 1] is 5
|
||||
# fg color 256
|
||||
i += 2
|
||||
fg = params[i] & 0xff
|
||||
@curAttr.fg = params[i] & 0xff
|
||||
else if p is 48
|
||||
if params[i + 1] is 2
|
||||
# bg color 2^24
|
||||
i += 2
|
||||
bg = "#" + params[i] & 0xff +
|
||||
params[i + 1] & 0xff +
|
||||
params[i + 2] & 0xff
|
||||
@curAttr.bg = "rgb(#{params[i]}, #{params[i+1]}, #{params[i+2]})"
|
||||
i += 2
|
||||
else if params[i + 1] is 5
|
||||
# bg color 256
|
||||
i += 2
|
||||
bg = params[i] & 0xff
|
||||
@curAttr.bg = params[i] & 0xff
|
||||
else if p is 100
|
||||
# reset fg/bg
|
||||
fg = (@defAttr >> 9) & 0x1ff
|
||||
bg = @defAttr & 0x1ff
|
||||
@curAttr.fg = 0
|
||||
@curAttr.bg = 256
|
||||
else
|
||||
console.error "Unknown SGR attribute: %d.", p
|
||||
i++
|
||||
@curAttr = (flags << 18) | (fg << 9) | bg
|
||||
|
||||
|
||||
# CSI Ps n Device Status Report (DSR).
|
||||
# Ps = 5 -> Status Report. Result (``OK'') is
|
||||
|
||||
Reference in New Issue
Block a user