feat: STM32 Renode SSD1306 OLED 지원
- mocks-stm32.ts: _RN_SSD1306_MOCK_H 추가 - 5×7 소프트웨어 폰트 포함 (96 ASCII) - 내부 framebuffer + display() → L:oD: 텔레메트리 - Wire stub, GFX base class (_RN_GFX_DEFINED 가드) - routes-arduino.ts: SSD1306 감지 → mock 주입 - arduino-emulator.html: L:O: (초기화) + L:oD: (프레임) 핸들러 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3125,7 +3125,51 @@ function _stm32ParseGpio(raw) {
|
||||
return out;
|
||||
}
|
||||
|
||||
let _stm32OledInited = false;
|
||||
let _stm32OledW = 128, _stm32OledH = 64;
|
||||
|
||||
function _stm32OledFlush(hexStr, inv) {
|
||||
const c = document.getElementById('oled-canvas');
|
||||
if (!c) return;
|
||||
const ctx = c.getContext('2d');
|
||||
const pages = _stm32OledH / 8;
|
||||
const img = ctx.createImageData(c.width, c.height);
|
||||
const sx = c.width / _stm32OledW, sy = c.height / _stm32OledH;
|
||||
for (let page = 0; page < pages; page++) {
|
||||
for (let col = 0; col < _stm32OledW; col++) {
|
||||
const idx = (page * _stm32OledW + col) * 2;
|
||||
const byte = parseInt(hexStr.slice(idx, idx + 2), 16) || 0;
|
||||
for (let bit = 0; bit < 8; bit++) {
|
||||
const on = !!((byte >> bit) & 1) !== inv;
|
||||
const row = page * 8 + bit;
|
||||
const r = on ? 0x60 : 0, g = on ? 0xa5 : 0, b = on ? 0xfa : 0;
|
||||
for (let dy = 0; dy < sy; dy++) for (let dx = 0; dx < sx; dx++) {
|
||||
const pi = ((Math.floor(row * sy) + dy) * c.width + Math.floor(col * sx) + dx) * 4;
|
||||
img.data[pi] = r; img.data[pi+1] = g; img.data[pi+2] = b; img.data[pi+3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.putImageData(img, 0, 0);
|
||||
oledSetActive(true);
|
||||
}
|
||||
|
||||
function _stm32LcdDraw(op, data) {
|
||||
// SSD1306 OLED 초기화
|
||||
if (op === 'O') {
|
||||
const [w, h] = data.split(',').map(Number);
|
||||
_stm32OledW = w || 128; _stm32OledH = h || 64;
|
||||
_stm32OledInited = true;
|
||||
const c = document.getElementById('oled-canvas');
|
||||
if (c) { c.width = _stm32OledW * 2; c.height = _stm32OledH * 2; }
|
||||
oledSetActive(true);
|
||||
return;
|
||||
}
|
||||
// SSD1306 프레임 데이터 (대문자=정상, 소문자=반전)
|
||||
if (op === 'oD' || op === 'od') {
|
||||
_stm32OledFlush(data, op === 'od');
|
||||
return;
|
||||
}
|
||||
if (op === 'I') {
|
||||
const [w, h] = data.split(',').map(Number);
|
||||
_esp32TftW = w || 240; _esp32TftH = h || 320; _esp32TftCtx2d = null;
|
||||
@@ -3141,13 +3185,13 @@ function _stm32LcdDraw(op, data) {
|
||||
}
|
||||
const n = data.split(',').map(Number);
|
||||
switch (op) {
|
||||
case 'r': _esp32TftDraw('B:' + n.join(',')); break; // fillRect x,y,w,h,c
|
||||
case 'h': _esp32TftDraw('B:' + [n[0],n[1],n[2],1,n[3]].join(',')); break; // hline → fillRect h=1
|
||||
case 'v': _esp32TftDraw('B:' + [n[0],n[1],1,n[2],n[3]].join(',')); break; // vline → fillRect w=1
|
||||
case 'p': _esp32TftDraw('P:' + n.join(',')); break; // pixel x,y,c
|
||||
case 'l': _esp32TftDraw('L:' + n.join(',')); break; // line x0,y0,x1,y1,c
|
||||
case 'c': _esp32TftDraw('C:' + [n[0],n[1],n[2],n[4],n[3]].join(',')); break; // circle cx,cy,r,fill,c → C:cx,cy,r,c,fill
|
||||
case 't': _esp32TftDraw('T:' + n.join(',')); break; // char x,y,fg,bg,size,charcode
|
||||
case 'r': _esp32TftDraw('B:' + n.join(',')); break;
|
||||
case 'h': _esp32TftDraw('B:' + [n[0],n[1],n[2],1,n[3]].join(',')); break;
|
||||
case 'v': _esp32TftDraw('B:' + [n[0],n[1],1,n[2],n[3]].join(',')); break;
|
||||
case 'p': _esp32TftDraw('P:' + n.join(',')); break;
|
||||
case 'l': _esp32TftDraw('L:' + n.join(',')); break;
|
||||
case 'c': _esp32TftDraw('C:' + [n[0],n[1],n[2],n[4],n[3]].join(',')); break;
|
||||
case 't': _esp32TftDraw('T:' + n.join(',')); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user