diff --git a/EPD/EPD_driver.h b/EPD/EPD_driver.h index 3a1887f..fd1af4b 100644 --- a/EPD/EPD_driver.h +++ b/EPD/EPD_driver.h @@ -37,6 +37,8 @@ typedef struct void (*sleep)(void); /**< Enter sleep mode */ int8_t (*read_temp)(void); /**< Read temperature from driver chip */ void (*force_temp)(int8_t value); /**< Force temperature (will trigger OTP LUT switch) */ + uint8_t cmd_write_ram1; /**< Command to write black ram */ + uint8_t cmd_write_ram2; /**< Command to write red ram */ } epd_driver_t; typedef enum diff --git a/EPD/EPD_service.c b/EPD/EPD_service.c index 2909fe6..5111468 100644 --- a/EPD/EPD_service.c +++ b/EPD/EPD_service.c @@ -151,6 +151,15 @@ static void epd_service_on_write(ble_epd_t * p_epd, uint8_t * p_data, uint16_t l ble_epd_on_timer(p_epd, timestamp, true); } break; + case EPD_CMD_WRITE_IMAGE: // MSB=0000: ram begin, LSB=1111: black + if (length < 3) return; + if ((p_data[1] >> 4) == 0x00) { + bool black = (p_data[1] & 0x0F) == 0x0F; + EPD_WriteCommand(black ? p_epd->epd->drv->cmd_write_ram1 : p_epd->epd->drv->cmd_write_ram2); + } + EPD_WriteData(&p_data[2], length - 2); + break; + case EPD_CMD_SET_CONFIG: if (length < 2) return; memcpy(&p_epd->config, &p_data[1], (length - 1 > EPD_CONFIG_SIZE) ? EPD_CONFIG_SIZE : length - 1); diff --git a/EPD/EPD_service.h b/EPD/EPD_service.h index 723c165..569fb2d 100644 --- a/EPD/EPD_service.h +++ b/EPD/EPD_service.h @@ -72,6 +72,8 @@ enum EPD_CMDS EPD_CMD_SET_TIME = 0x20, /** < set time with unix timestamp */ + EPD_CMD_WRITE_IMAGE = 0x30, /** < write image data to EPD ram */ + EPD_CMD_SET_CONFIG = 0x90, /**< set full EPD config */ EPD_CMD_SYS_RESET = 0x91, /**< MCU reset */ EPD_CMD_SYS_SLEEP = 0x92, /**< MCU enter sleep mode */ diff --git a/EPD/SSD1619.c b/EPD/SSD1619.c index 86e6545..ded212f 100644 --- a/EPD/SSD1619.c +++ b/EPD/SSD1619.c @@ -183,6 +183,8 @@ static epd_driver_t epd_drv_ssd1619 = { .sleep = SSD1619_Sleep, .read_temp = SSD1619_Read_Temp, .force_temp = SSD1619_Force_Temp, + .cmd_write_ram1 = CMD_WRITE_RAM1, + .cmd_write_ram2 = CMD_WRITE_RAM2, }; // SSD1619 400x300 Black/White/Red diff --git a/EPD/UC8176.c b/EPD/UC8176.c index 3fb95be..52c23fd 100644 --- a/EPD/UC8176.c +++ b/EPD/UC8176.c @@ -230,6 +230,8 @@ static epd_driver_t epd_drv_uc8176 = { .sleep = UC8176_Sleep, .read_temp = UC8176_Read_Temp, .force_temp = UC8176_Force_Temp, + .cmd_write_ram1 = CMD_DTM1, + .cmd_write_ram2 = CMD_DTM2, }; // UC8176 400x300 Black/White diff --git a/html/js/dithering.js b/html/js/dithering.js index 9be0141..9920712 100644 --- a/html/js/dithering.js +++ b/html/js/dithering.js @@ -82,7 +82,7 @@ function dithering(ctx, width, height, threshold, type) { } // white: 1, black/red: 0 -function canvas2bytes(canvas, type='bw', invert = false) { +function canvas2bytes(canvas, step = 'bw', invert = false) { const ctx = canvas.getContext("2d"); const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); @@ -92,7 +92,7 @@ function canvas2bytes(canvas, type='bw', invert = false) { for (let y = 0; y < canvas.height; y++) { for (let x = 0; x < canvas.width; x++) { const i = (canvas.width * y + x) * 4; - if (type !== 'red') { + if (step === 'bw') { buffer.push(imageData.data[i] === 0 && imageData.data[i+1] === 0 && imageData.data[i+2] === 0 ? 0 : 1); } else { buffer.push(imageData.data[i] > 0 && imageData.data[i+1] === 0 && imageData.data[i+2] === 0 ? 0 : 1); diff --git a/html/js/main.js b/html/js/main.js index dd09f4a..da00d69 100644 --- a/html/js/main.js +++ b/html/js/main.js @@ -14,6 +14,8 @@ const EpdCmd = { SET_TIME: 0x20, + WRITE_IMG: 0x30, // v1.6 + SET_CONFIG: 0x90, SYS_RESET: 0x91, SYS_SLEEP: 0x92, @@ -77,6 +79,32 @@ async function epdWrite(cmd, data) { } } +async function epdWriteImage(step = 'bw') { + const data = canvas2bytes(canvas, step); + const chunkSize = document.getElementById('mtusize').value - 2; + const interleavedCount = document.getElementById('interleavedcount').value; + const count = Math.round(data.length / chunkSize); + let chunkIdx = 0; + let noReplyCount = interleavedCount; + + for (let i = 0; i < data.length; i += chunkSize) { + let currentTime = (new Date().getTime() - startTime) / 1000.0; + setStatus(`${step == 'bw' ? '黑白' : '红色'}块: ${chunkIdx+1}/${count+1}, 总用时: ${currentTime}s`); + const payload = [ + (step == 'bw' ? 0x0F : 0x00) | ( i == 0 ? 0x00 : 0xF0), + ...data.slice(i, i + chunkSize), + ]; + if (noReplyCount > 0) { + await write(EpdCmd.WRITE_IMG, payload, false); + noReplyCount--; + } else { + await write(EpdCmd.WRITE_IMG, payload, true); + noReplyCount = interleavedCount; + } + chunkIdx++; + } +} + async function setDriver() { await write(EpdCmd.SET_PINS, document.getElementById("epdpins").value); await write(EpdCmd.INIT, document.getElementById("epddriver").value); @@ -123,12 +151,16 @@ async function sendimg() { startTime = new Date().getTime(); status.parentElement.style.display = "block"; - if (mode.startsWith('bwr')) { - const invert = (appVersion < 0x16) ? (driver === '02') : false; - await epdWrite(driver === "02" ? 0x24 : 0x10, canvas2bytes(canvas, 'bw')); - await epdWrite(driver === "02" ? 0x26 : 0x13, canvas2bytes(canvas, 'red', invert)); + if (appVersion < 0x16) { + if (mode.startsWith('bwr')) { + await epdWrite(driver === "02" ? 0x24 : 0x10, canvas2bytes(canvas, 'bw')); + await epdWrite(driver === "02" ? 0x26 : 0x13, canvas2bytes(canvas, 'red', driver === '02')); + } else { + await epdWrite(driver === "04" ? 0x24 : 0x13, canvas2bytes(canvas, 'bw')); + } } else { - await epdWrite(driver === "04" ? 0x24 : 0x13, canvas2bytes(canvas, 'bw')); + await epdWriteImage('bw'); + if (mode.startsWith('bwr')) await epdWriteImage('red'); } await write(EpdCmd.REFRESH);