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:
@@ -60,6 +60,7 @@ static inline void _rn_lt5(char op, int16_t a, int16_t b, int16_t c, int16_t d,
|
||||
/* ══════════════════════════════════════════════════════
|
||||
Adafruit_GFX — complete replacement, no SPI
|
||||
══════════════════════════════════════════════════════ */
|
||||
#define _RN_GFX_DEFINED
|
||||
class Adafruit_GFX : public Print {
|
||||
protected:
|
||||
int16_t _width, _height;
|
||||
@@ -184,3 +185,216 @@ public:
|
||||
|
||||
#endif /* _RN_ILI9341_MOCK_H */
|
||||
`;
|
||||
|
||||
export const _RN_SSD1306_MOCK_H = `#pragma once
|
||||
#ifndef _RN_SSD1306_MOCK_H
|
||||
#define _RN_SSD1306_MOCK_H
|
||||
#include <Arduino.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SSD1306_SWITCHCAPVCC 0x02
|
||||
#define SSD1306_EXTERNALVCC 0x01
|
||||
#define SSD1306_BLACK 0
|
||||
#define SSD1306_WHITE 1
|
||||
#define SSD1306_INVERSE 2
|
||||
#ifndef BLACK
|
||||
#define BLACK SSD1306_BLACK
|
||||
#define WHITE SSD1306_WHITE
|
||||
#define INVERSE SSD1306_INVERSE
|
||||
#endif
|
||||
|
||||
/* ── Wire stub (SSD1306 mock이 실제로 I2C를 사용하지 않음) ── */
|
||||
#ifndef _RN_WIRE_STUB
|
||||
#define _RN_WIRE_STUB
|
||||
class TwoWire {
|
||||
public:
|
||||
void begin() {} void begin(uint8_t,uint8_t) {} void setClock(uint32_t) {}
|
||||
void beginTransmission(uint8_t) {} uint8_t endTransmission(bool=true){return 0;}
|
||||
uint8_t requestFrom(uint8_t,uint8_t){return 0;}
|
||||
size_t write(uint8_t){return 1;} size_t write(const uint8_t*,size_t n){return n;}
|
||||
int available(){return 0;} int read(){return -1;} int peek(){return -1;}
|
||||
};
|
||||
static TwoWire Wire;
|
||||
#endif
|
||||
|
||||
/* ── Minimal GFX base (ILI9341 mock가 없을 때만 정의) ── */
|
||||
#ifndef _RN_GFX_DEFINED
|
||||
#define _RN_GFX_DEFINED
|
||||
struct GFXfont { const uint8_t* bitmap; const void* glyph; uint8_t first,last,yAdvance; };
|
||||
|
||||
static const uint8_t _SSD_FONT5X7[96][5] = {
|
||||
{0x00,0x00,0x00,0x00,0x00},{0x00,0x00,0x5F,0x00,0x00},{0x00,0x07,0x00,0x07,0x00},
|
||||
{0x14,0x7F,0x14,0x7F,0x14},{0x24,0x2A,0x7F,0x2A,0x12},{0x23,0x13,0x08,0x64,0x62},
|
||||
{0x36,0x49,0x55,0x22,0x50},{0x00,0x05,0x03,0x00,0x00},{0x00,0x1C,0x22,0x41,0x00},
|
||||
{0x00,0x41,0x22,0x1C,0x00},{0x14,0x08,0x3E,0x08,0x14},{0x08,0x08,0x3E,0x08,0x08},
|
||||
{0x00,0x50,0x30,0x00,0x00},{0x08,0x08,0x08,0x08,0x08},{0x00,0x60,0x60,0x00,0x00},
|
||||
{0x20,0x10,0x08,0x04,0x02},{0x3E,0x51,0x49,0x45,0x3E},{0x00,0x42,0x7F,0x40,0x00},
|
||||
{0x42,0x61,0x51,0x49,0x46},{0x21,0x41,0x45,0x4B,0x31},{0x18,0x14,0x12,0x7F,0x10},
|
||||
{0x27,0x45,0x45,0x45,0x39},{0x3C,0x4A,0x49,0x49,0x30},{0x01,0x71,0x09,0x05,0x03},
|
||||
{0x36,0x49,0x49,0x49,0x36},{0x06,0x49,0x49,0x29,0x1E},{0x00,0x36,0x36,0x00,0x00},
|
||||
{0x00,0x56,0x36,0x00,0x00},{0x08,0x14,0x22,0x41,0x00},{0x14,0x14,0x14,0x14,0x14},
|
||||
{0x00,0x41,0x22,0x14,0x08},{0x02,0x01,0x51,0x09,0x06},{0x32,0x49,0x79,0x41,0x3E},
|
||||
{0x7E,0x11,0x11,0x11,0x7E},{0x7F,0x49,0x49,0x49,0x36},{0x3E,0x41,0x41,0x41,0x22},
|
||||
{0x7F,0x41,0x41,0x22,0x1C},{0x7F,0x49,0x49,0x49,0x41},{0x7F,0x09,0x09,0x09,0x01},
|
||||
{0x3E,0x41,0x49,0x49,0x7A},{0x7F,0x08,0x08,0x08,0x7F},{0x00,0x41,0x7F,0x41,0x00},
|
||||
{0x20,0x40,0x41,0x3F,0x01},{0x7F,0x08,0x14,0x22,0x41},{0x7F,0x40,0x40,0x40,0x40},
|
||||
{0x7F,0x02,0x0C,0x02,0x7F},{0x7F,0x04,0x08,0x10,0x7F},{0x3E,0x41,0x41,0x41,0x3E},
|
||||
{0x7F,0x09,0x09,0x09,0x06},{0x3E,0x41,0x51,0x21,0x5E},{0x7F,0x09,0x19,0x29,0x46},
|
||||
{0x46,0x49,0x49,0x49,0x31},{0x01,0x01,0x7F,0x01,0x01},{0x3F,0x40,0x40,0x40,0x3F},
|
||||
{0x1F,0x20,0x40,0x20,0x1F},{0x3F,0x40,0x38,0x40,0x3F},{0x63,0x14,0x08,0x14,0x63},
|
||||
{0x07,0x08,0x70,0x08,0x07},{0x61,0x51,0x49,0x45,0x43},{0x00,0x7F,0x41,0x41,0x00},
|
||||
{0x02,0x04,0x08,0x10,0x20},{0x00,0x41,0x41,0x7F,0x00},{0x04,0x02,0x01,0x02,0x04},
|
||||
{0x40,0x40,0x40,0x40,0x40},{0x00,0x01,0x02,0x04,0x00},{0x20,0x54,0x54,0x54,0x78},
|
||||
{0x7F,0x48,0x44,0x44,0x38},{0x38,0x44,0x44,0x44,0x20},{0x38,0x44,0x44,0x48,0x7F},
|
||||
{0x38,0x54,0x54,0x54,0x18},{0x08,0x7E,0x09,0x01,0x02},{0x0C,0x52,0x52,0x52,0x3E},
|
||||
{0x7F,0x08,0x04,0x04,0x78},{0x00,0x44,0x7D,0x40,0x00},{0x20,0x40,0x44,0x3D,0x00},
|
||||
{0x7F,0x10,0x28,0x44,0x00},{0x00,0x41,0x7F,0x40,0x00},{0x7C,0x04,0x18,0x04,0x78},
|
||||
{0x7C,0x08,0x04,0x04,0x78},{0x38,0x44,0x44,0x44,0x38},{0x7C,0x14,0x14,0x14,0x08},
|
||||
{0x08,0x14,0x14,0x18,0x7C},{0x7C,0x08,0x04,0x04,0x08},{0x48,0x54,0x54,0x54,0x20},
|
||||
{0x04,0x3F,0x44,0x40,0x20},{0x3C,0x40,0x40,0x40,0x3C},{0x1C,0x20,0x40,0x20,0x1C},
|
||||
{0x3C,0x40,0x30,0x40,0x3C},{0x44,0x28,0x10,0x28,0x44},{0x0C,0x50,0x50,0x50,0x3C},
|
||||
{0x44,0x64,0x54,0x4C,0x44},{0x00,0x08,0x36,0x41,0x00},{0x00,0x00,0x7F,0x00,0x00},
|
||||
{0x00,0x41,0x36,0x08,0x00},{0x10,0x08,0x08,0x10,0x08},{0x3C,0x26,0x23,0x26,0x3C},
|
||||
};
|
||||
|
||||
class Print {
|
||||
public:
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
size_t print(const char* s){ size_t n=0; if(s) while(*s) n+=write((uint8_t)*s++); return n; }
|
||||
size_t println(const char* s){ return print(s)+write('\\n'); }
|
||||
size_t print(int v, int=10){ char b[16]; snprintf(b,sizeof(b),"%d",v); return print(b); }
|
||||
size_t println(int v, int=10){ return print(v)+write('\\n'); }
|
||||
size_t print(long v, int=10){ char b[24]; snprintf(b,sizeof(b),"%ld",v); return print(b); }
|
||||
size_t println(long v, int=10){ return print(v)+write('\\n'); }
|
||||
size_t print(unsigned v, int=10){ char b[16]; snprintf(b,sizeof(b),"%u",v); return print(b); }
|
||||
size_t print(float v, int d=2){ char b[24]; char fmt[8]; snprintf(fmt,sizeof(fmt),"%%.%df",d); snprintf(b,sizeof(b),fmt,v); return print(b); }
|
||||
size_t println(float v, int d=2){ return print(v,d)+write('\\n'); }
|
||||
size_t println(){ return write('\\n'); }
|
||||
};
|
||||
|
||||
class Adafruit_GFX : public Print {
|
||||
protected:
|
||||
int16_t _width, _height, _cx=0, _cy=0;
|
||||
uint16_t _fg=1, _bg=0;
|
||||
uint8_t _ts=1;
|
||||
public:
|
||||
Adafruit_GFX(int16_t w,int16_t h):_width(w),_height(h){}
|
||||
virtual void drawPixel(int16_t x,int16_t y,uint16_t c)=0;
|
||||
int16_t width()const{return _width;} int16_t height()const{return _height;}
|
||||
void setTextColor(uint16_t c){_fg=c;} void setTextColor(uint16_t f,uint16_t b){_fg=f;_bg=b;}
|
||||
void setTextSize(uint8_t s){_ts=s?s:1;} void setCursor(int16_t x,int16_t y){_cx=x;_cy=y;}
|
||||
void setFont(const GFXfont*){} void setTextWrap(bool){}
|
||||
int16_t getCursorX()const{return _cx;} int16_t getCursorY()const{return _cy;}
|
||||
|
||||
void fillScreen(uint16_t c){fillRect(0,0,_width,_height,c);}
|
||||
void fillRect(int16_t x,int16_t y,int16_t w,int16_t h,uint16_t c){
|
||||
for(int j=y;j<y+h;j++) for(int i=x;i<x+w;i++) drawPixel(i,j,c);
|
||||
}
|
||||
void drawRect(int16_t x,int16_t y,int16_t w,int16_t h,uint16_t c){
|
||||
for(int i=x;i<x+w;i++){drawPixel(i,y,c);drawPixel(i,y+h-1,c);}
|
||||
for(int j=y+1;j<y+h-1;j++){drawPixel(x,j,c);drawPixel(x+w-1,j,c);}
|
||||
}
|
||||
void drawFastHLine(int16_t x,int16_t y,int16_t w,uint16_t c){fillRect(x,y,w,1,c);}
|
||||
void drawFastVLine(int16_t x,int16_t y,int16_t h,uint16_t c){fillRect(x,y,1,h,c);}
|
||||
void drawLine(int16_t x0,int16_t y0,int16_t x1,int16_t y1,uint16_t c){
|
||||
int dx=abs(x1-x0),dy=-abs(y1-y0),sx=x0<x1?1:-1,sy=y0<y1?1:-1,e=dx+dy,e2;
|
||||
while(true){drawPixel(x0,y0,c);if(x0==x1&&y0==y1)break;e2=2*e;if(e2>=dy){e+=dy;x0+=sx;}if(e2<=dx){e+=dx;y0+=sy;}}
|
||||
}
|
||||
void drawCircle(int16_t cx,int16_t cy,int16_t r,uint16_t c){
|
||||
int x=0,y=r,d=3-2*r;
|
||||
while(y>=x){
|
||||
drawPixel(cx+x,cy+y,c);drawPixel(cx-x,cy+y,c);drawPixel(cx+x,cy-y,c);drawPixel(cx-x,cy-y,c);
|
||||
drawPixel(cx+y,cy+x,c);drawPixel(cx-y,cy+x,c);drawPixel(cx+y,cy-x,c);drawPixel(cx-y,cy-x,c);
|
||||
d<0?d+=4*x+6:(d+=4*(x-y)+10,y--);x++;
|
||||
}
|
||||
}
|
||||
void fillCircle(int16_t cx,int16_t cy,int16_t r,uint16_t c){
|
||||
for(int y=-r;y<=r;y++) for(int x=-r;x<=r;x++) if(x*x+y*y<=r*r) drawPixel(cx+x,cy+y,c);
|
||||
}
|
||||
void drawRoundRect(int16_t x,int16_t y,int16_t w,int16_t h,int16_t,uint16_t c){drawRect(x,y,w,h,c);}
|
||||
void fillRoundRect(int16_t x,int16_t y,int16_t w,int16_t h,int16_t,uint16_t c){fillRect(x,y,w,h,c);}
|
||||
void drawTriangle(int16_t x0,int16_t y0,int16_t x1,int16_t y1,int16_t x2,int16_t y2,uint16_t c){
|
||||
drawLine(x0,y0,x1,y1,c);drawLine(x1,y1,x2,y2,c);drawLine(x2,y2,x0,y0,c);
|
||||
}
|
||||
void fillTriangle(int16_t x0,int16_t y0,int16_t x1,int16_t y1,int16_t x2,int16_t y2,uint16_t c){
|
||||
drawTriangle(x0,y0,x1,y1,x2,y2,c);
|
||||
}
|
||||
static uint16_t color565(uint8_t r,uint8_t g,uint8_t b){
|
||||
return ((uint16_t)(r&0xF8)<<8)|((uint16_t)(g&0xFC)<<3)|(b>>3);
|
||||
}
|
||||
size_t write(uint8_t ch) override {
|
||||
if(ch=='\\n'){_cy+=8*_ts;_cx=0;return 1;}
|
||||
if(ch=='\\r')return 1;
|
||||
if(ch<0x20||ch>0x7F)ch='?';
|
||||
const uint8_t* col=_SSD_FONT5X7[ch-0x20];
|
||||
for(int c=0;c<5;c++){
|
||||
uint8_t line=col[c];
|
||||
for(int r=0;r<8;r++,line>>=1)
|
||||
drawPixel(_cx+c*_ts,_cy+r*_ts,(line&1)?_fg:_bg);
|
||||
}
|
||||
_cx+=6*_ts;
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
#endif /* _RN_GFX_DEFINED */
|
||||
|
||||
/* ══════════════════════════════════════════════════════
|
||||
Adafruit_SSD1306 — framebuffer + UART telemetry
|
||||
══════════════════════════════════════════════════════ */
|
||||
class Adafruit_SSD1306 : public Adafruit_GFX {
|
||||
uint8_t _buf[1024]; // 128×64 / 8 pages
|
||||
bool _inited = false;
|
||||
bool _inv = false;
|
||||
public:
|
||||
// I2C constructor
|
||||
Adafruit_SSD1306(uint8_t w,uint8_t h,TwoWire* =nullptr,int8_t=-1)
|
||||
: Adafruit_GFX(w,h){ memset(_buf,0,sizeof(_buf)); }
|
||||
// SPI constructor
|
||||
Adafruit_SSD1306(uint8_t w,uint8_t h,int8_t,int8_t,int8_t,int8_t,int8_t=-1)
|
||||
: Adafruit_GFX(w,h){ memset(_buf,0,sizeof(_buf)); }
|
||||
|
||||
bool begin(uint8_t=SSD1306_SWITCHCAPVCC,uint8_t=0x3C,bool=true,bool=true){
|
||||
_inited=true;
|
||||
char b[16]; snprintf(b,sizeof(b),"L:O:%d,%d",(int)_width,(int)_height);
|
||||
Serial.write((uint8_t)2); Serial.print(b); Serial.write((uint8_t)3);
|
||||
return true;
|
||||
}
|
||||
|
||||
void clearDisplay(){ memset(_buf,0,sizeof(_buf)); }
|
||||
|
||||
void drawPixel(int16_t x,int16_t y,uint16_t color) override {
|
||||
if(x<0||x>=_width||y<0||y>=_height) return;
|
||||
const int page=y/8, bit=y&7;
|
||||
if(color) _buf[x+page*_width]|= (1<<bit);
|
||||
else _buf[x+page*_width]&=~(1<<bit);
|
||||
}
|
||||
|
||||
void display(){
|
||||
if(!_inited) return;
|
||||
static const char HEX[]="0123456789ABCDEF";
|
||||
const int pages=_height/8;
|
||||
Serial.write((uint8_t)2);
|
||||
Serial.print(_inv?"L:od:":"L:oD:");
|
||||
for(int i=0;i<_width*pages;i++){
|
||||
Serial.write((uint8_t)HEX[_buf[i]>>4]);
|
||||
Serial.write((uint8_t)HEX[_buf[i]&0xF]);
|
||||
}
|
||||
Serial.write((uint8_t)3);
|
||||
}
|
||||
|
||||
void invertDisplay(bool i){ _inv=i; }
|
||||
void dim(bool){}
|
||||
void startScrollRight(uint8_t,uint8_t){}
|
||||
void startScrollLeft(uint8_t,uint8_t){}
|
||||
void startScrollDiagRight(uint8_t,uint8_t){}
|
||||
void startScrollDiagLeft(uint8_t,uint8_t){}
|
||||
void stopScroll(){}
|
||||
void ssd1306_command(uint8_t){}
|
||||
bool getPixel(int16_t x,int16_t y)const{
|
||||
if(x<0||x>=_width||y<0||y>=_height) return false;
|
||||
return (_buf[x+(y/8)*_width]>>(y&7))&1;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _RN_SSD1306_MOCK_H */
|
||||
`;
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
_WIRE_MOCK_H,_MPU6050_MOCK_H,_BME280_MOCK_H,_ONEWIRE_MOCK_H,_DALLASTEMP_MOCK_H,
|
||||
_RELAY_MOCK_H,_L298N_MOCK_H,_SPI_MOCK_H,_TFT_MOCK_H,
|
||||
} from './mocks-esp32';
|
||||
import { _RN_ILI9341_MOCK_H } from './mocks-stm32';
|
||||
import { _RN_ILI9341_MOCK_H, _RN_SSD1306_MOCK_H } from './mocks-stm32';
|
||||
|
||||
export function registerArduinoRoutes(app: express.Application, getSessionUser: (req: express.Request) => any): void {
|
||||
|
||||
@@ -2013,6 +2013,32 @@ app.post('/api/arduino/renode/start', async (req, res) => {
|
||||
.replace(/&(SPI\d+)\b/g, 'nullptr');
|
||||
}
|
||||
|
||||
// SSD1306 OLED 사용 시: 실제 라이브러리를 로컬 mock으로 교체
|
||||
const _hasSSD1306 = /Adafruit_SSD1306\.h/.test(patchedCode);
|
||||
if (_hasSSD1306) {
|
||||
const fs3 = require('fs');
|
||||
fs3.writeFileSync(sketchDir + '/Adafruit_SSD1306.h', _RN_SSD1306_MOCK_H);
|
||||
if (!_hasILI9341) {
|
||||
// ILI9341 mock가 없으면 GFX 헤더도 SSD1306 mock에서 제공
|
||||
fs3.writeFileSync(sketchDir + '/Adafruit_GFX.h', '#pragma once\n#include "Adafruit_SSD1306.h"\n');
|
||||
patchedCode = patchedCode.replace(/#include\s*<Adafruit_GFX\.h>/g, '#include "Adafruit_GFX.h"');
|
||||
}
|
||||
// Wire.h stub (SSD1306 I2C init 컴파일 통과용)
|
||||
if (!fs3.existsSync(sketchDir + '/Wire.h')) {
|
||||
fs3.writeFileSync(sketchDir + '/Wire.h',
|
||||
'#pragma once\nclass TwoWire{\npublic:\n void begin(){} void begin(uint8_t,uint8_t){} void setClock(uint32_t){}\n' +
|
||||
' void beginTransmission(uint8_t){} uint8_t endTransmission(bool=true){return 0;}\n' +
|
||||
' uint8_t requestFrom(uint8_t,uint8_t){return 0;}\n' +
|
||||
' size_t write(uint8_t){return 1;} size_t write(const uint8_t*,size_t n){return n;}\n' +
|
||||
' int available(){return 0;} int read(){return -1;} int peek(){return -1;}\n};\n' +
|
||||
'static TwoWire Wire;\n'
|
||||
);
|
||||
patchedCode = patchedCode.replace(/#include\s*<Wire\.h>/g, '#include "Wire.h"');
|
||||
}
|
||||
patchedCode = patchedCode
|
||||
.replace(/#include\s*<Adafruit_SSD1306\.h>/g, '#include "Adafruit_SSD1306.h"');
|
||||
}
|
||||
|
||||
require('fs').writeFileSync(sketchDir + '/sketch.ino', patchedCode);
|
||||
|
||||
const execQ = (cmd: string, ms = 60000): Promise<{ stdout: string; stderr: string }> =>
|
||||
|
||||
@@ -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