plasma: ESC P bitmap rows through the feedback endpoint (plasma row)
PlasmaCommands.GraphicsWrite/GraphicsRow port the display firmware graphics command (ESC P s y x w h, MSB-left); PlasmaDisplay.RowAsync writes a locked whole-row update; the line protocol gains `plasma row <y> <hex32>`. The router plasma slot becomes a bounded FIFO queue: rows stream in order (a frame must not tear), texts still coalesce to the newest, clear flushes, cap 128 with counted drops. Docs updated; 442 tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -145,7 +145,7 @@ public static class FeedbackLineParser
|
||||
string? sub = NextToken(s, ref pos);
|
||||
if (sub is null)
|
||||
{
|
||||
error = "plasma needs a subcommand (text|clear)";
|
||||
error = "plasma needs a subcommand (text|clear|row)";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -163,12 +163,82 @@ public static class FeedbackLineParser
|
||||
case "text":
|
||||
return TryParsePlasmaText(s, pos, out command, out error);
|
||||
|
||||
case "row":
|
||||
return TryParsePlasmaRow(s, pos, out command, out error);
|
||||
|
||||
default:
|
||||
error = $"unknown plasma subcommand '{sub}'";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// plasma row <y> <32 hex digits>: one full 128-px bitmap row (16 bytes,
|
||||
// MSB = leftmost pixel), matching the native game's whole-row streaming.
|
||||
private static bool TryParsePlasmaRow(
|
||||
string s, int pos, out FeedbackCommand? command, out string? error)
|
||||
{
|
||||
command = null;
|
||||
error = null;
|
||||
|
||||
string? yToken = NextToken(s, ref pos);
|
||||
if (yToken is null || !TryParseNumber(yToken, out int y))
|
||||
{
|
||||
error = "plasma row needs a row number and 32 hex digits";
|
||||
return false;
|
||||
}
|
||||
if (y is < 0 or > 31)
|
||||
{
|
||||
error = $"plasma row {y} out of range (0-31)";
|
||||
return false;
|
||||
}
|
||||
|
||||
string? hex = NextToken(s, ref pos);
|
||||
if (hex is null)
|
||||
{
|
||||
error = "plasma row needs 32 hex digits of row data";
|
||||
return false;
|
||||
}
|
||||
if (NextToken(s, ref pos) is string extra)
|
||||
{
|
||||
error = $"unexpected token '{extra}'";
|
||||
return false;
|
||||
}
|
||||
if (hex.Length != 32)
|
||||
{
|
||||
error = $"plasma row data must be exactly 32 hex digits (16 bytes), got {hex.Length}";
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = new byte[16];
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
int hi = HexNibble(hex[i * 2]);
|
||||
int lo = HexNibble(hex[i * 2 + 1]);
|
||||
if (hi < 0 || lo < 0)
|
||||
{
|
||||
error = $"plasma row data has a non-hex character ('{hex[hi < 0 ? i * 2 : i * 2 + 1]}')";
|
||||
return false;
|
||||
}
|
||||
data[i] = (byte)((hi << 4) | lo);
|
||||
}
|
||||
|
||||
command = new FeedbackCommand
|
||||
{
|
||||
Kind = FeedbackCommandKind.PlasmaRow,
|
||||
Y = (byte)y,
|
||||
Data = data,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int HexNibble(char c) => c switch
|
||||
{
|
||||
>= '0' and <= '9' => c - '0',
|
||||
>= 'a' and <= 'f' => c - 'a' + 10,
|
||||
>= 'A' and <= 'F' => c - 'A' + 10,
|
||||
_ => -1,
|
||||
};
|
||||
|
||||
private static bool TryParsePlasmaText(
|
||||
string s, int pos, out FeedbackCommand? command, out string? error)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user