diff --git a/html/css/main.css b/html/css/main.css new file mode 100644 index 0000000..b379b1d --- /dev/null +++ b/html/css/main.css @@ -0,0 +1,271 @@ +:root { + --primary-color: #0d6efd; + --primary-hover: #0b5ed7; + --secondary-color: #6c757d; + --secondary-hover: #5c636a; +} + +body { + margin: 0; + padding: 0; + font-family: system-ui, -apple-system, sans-serif; +} + +.main { + width: 100%; + max-width: 950px; + margin: 0 auto; + padding: 0 1rem; + background: #fff; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + box-sizing: border-box; +} + +.footer { + display: flex; + gap: 10px; + font-size: 0.8rem; + color: #666; +} + +.footer .links { + display: flex; + gap: 5px; + align-items: center; +} + +.footer a { + color: #666; + text-decoration: none; +} + +.footer a:hover { + color: #0d6efd; + text-decoration: underline; +} + +h3 { + padding-bottom: .3em; + border-bottom: 1px solid #CCC; + text-align: center; +} + +fieldset { + border: none; + box-shadow: 0 .5rem 0.5rem rgba(0, 0, 0, 0.2); + background-color: #f8f9fa; + padding: 10px; + margin-bottom: 16px; + border-radius: 4px; +} + +fieldset legend { + font-weight: bold; + color: rgba(0, 0, 255, 0.6); +} + +code { + padding: .2em .4em; + margin: 0; + font-size: 85%; + background: #CCC; + border-radius: 3px; +} + +.flex-container { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 10px; +} + +.left-controls { + display: flex; + flex-wrap: wrap; + gap: 8px; + align-items: center; +} + +.right-controls { + display: flex; + flex-wrap: wrap; + gap: 8px; + align-items: center; + margin-left: auto; +} + +.flex-group { + display: flex; + flex-wrap: wrap; + gap: 8px; + align-items: center; + margin-bottom: 8px; +} + +#status { + margin: 10px 0; +} + +#log { + width: 100%; + min-height: 100px; + max-height: 300px; + margin: 0; + padding: 5px; + background: #DDD; + overflow: auto; + font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; + box-sizing: border-box; +} + +#log .time { + color: #333; +} + +#log .action { + color: #666; +} + +#canvas-box { + margin-top: 10px; + width: 100%; +} + +#canvas { + border: black solid 1px; + max-width: 100%; + height: auto; + display: block; + margin: 0 auto; +} + +button { + padding: 0.375rem 0.75rem; + border: 1px solid var(--primary-color); + border-radius: 0.375rem; + margin-bottom: 5px; + white-space: nowrap; + cursor: pointer; + font-size: 0.9rem; +} + +button:disabled { + opacity: 0.65; +} + +button.primary { + color: #fff; + background-color: var(--primary-color); +} + +button.primary:hover { + color: #fff; + border-color: var(--primary-hover); + background-color: var(--primary-hover); +} + +button.secondary { + color: #fff; + background-color: var(--secondary-color); + border-color: var(--secondary-color); +} + +button.secondary:hover { + color: #fff; + border-color: var(--secondary-hover); + background-color: var(--secondary-hover); +} + +input[type=text], +input[type=number], +select { + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + border: 1px solid #dee2e6; + border-radius: 0.375rem; + padding: .2rem .75rem; + max-width: 100%; + box-sizing: border-box; +} + +input[type=file] { + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + max-width: 100%; +} + +input::file-selector-button { + font-size: 0.9rem; + font-weight: 400; + line-height: 1.5; + border: 1px solid var(--primary-color); + border-radius: 0.375rem; + cursor: pointer; +} + +select { + padding: .3rem 2.25rem .3rem .75rem; +} + +input:focus, +select:focus { + border: 1px solid #86b7fe; + box-shadow: 0 0 4px rgba(0, 120, 215, 0.8); + outline: 0; +} + +label { + margin-right: 4px; + white-space: nowrap; +} + +.status-bar { + display: none; + font-size: 85%; + color: #666; + margin-bottom: 10px; + padding-bottom: 10px; + border-bottom: 1px dotted #AAA; +} + +@media (max-width: 768px) { + .flex-container { + flex-direction: column; + } + + .left-controls, + .right-controls { + margin-left: 0; + width: 100%; + } + + .canvas-log-container { + flex-direction: column; + } + + #log { + height: 150px; + margin-top: 10px; + } + + fieldset { + padding: 8px; + } + + button { + width: auto; + } + + input[type=text], + input[type=number], + select { + max-width: 100%; + margin-bottom: 5px; + } +} \ No newline at end of file diff --git a/html/index.html b/html/index.html index 74aba6b..a5f84c7 100644 --- a/html/index.html +++ b/html/index.html @@ -1,147 +1,112 @@ - + - 4.2 寸电子墨水屏蓝牙控制器 - + 4.2 寸电子墨水屏蓝牙控制器 + -
-

4.2 寸电子墨水屏蓝牙控制器

-
- 蓝牙连接 -
-
- - -
-
- - - - - -
-
-
+
+

4.2 寸电子墨水屏蓝牙控制器

+
+ 蓝牙连接 +
+
+ + + +
+
+
+ + +
+
+ + +
+
+ +
+
+
+
+
+
+ 屏幕控制 +
+
+ + + +
+
+ + +
+
+
- 屏幕控制 -
-
- - - + 蓝牙传图 +
+ +
+
+
+ + +
+
+ + +
-
- - -
-
- - - +
+
状态:
+
+
+ +
-
状态:
-
-
-
- - - - - - -
- -
-
- -
-
-
-
-
- 提示 -

驱动板上 LED 灯(如果有的话)闪烁的时候表示墨水屏处于忙碌状态,此时上位机发送的指令可能不会被执行

-
    -
  • 日历模式: 点击“日历模式”按钮将自动从浏览器同步时间到墨水屏,并切换到日历显示,每天凌晨更新日历
  • -
  • - 时钟模式: 点击“时钟模式”按钮将自动从浏览器同步时间到墨水屏,并切换到时钟显示,每分钟刷新一次时间 -
      -
    • 此功能为预览版,不建议日常使用,目前使用全刷实现(以后可能会支持局刷)
    • -
    • 三色屏请不要开启时钟模式(刷新太慢,如误点开启可以传图或者清屏退出)
    • -
    -
  • -
  • 引脚配置:格式为十六进制,顺序:MOSI/SCLK/CS/DC/RST/BUSY/BS/EN,前面 7 个引脚配置为必须,EN 为可选(没有用到的引脚可配置为 FF
  • -
  • 确认间隔: 这个间隔指的是数据包数量间隔,即发送此数量的不确认响应的数据包后才发送一次需确认响应的数据包。加大此值可优化传图速度,但是丢包风险也更大(你可能会发现图片有部分位置显示不正常,此时需调小这个值) -
  • 指令列表: 支持的指令可在项目 README 查询(此功能一般只会在开发测试时用到) -
  • 灰度:目前仅 UC8176(黑白屏) 驱动支持 4 级灰度,其它驱动选择此选项结果未知
  • -
  • 开源地址: - tsl0922/EPD-nRF5, - 交流群:1033086563 -
  • -
-

- 系统睡眠后可通过线圈(NFC/无线充电器)唤醒(需正确配置线圈对应的引脚才有效),否则一旦系统睡眠只有重新上电才能开启蓝牙。如果价签上带有 LED,系统启动时 LED 会闪一下(需正确配置 LED 对应的引脚才有效),以便知道系统是否已经被线圈唤醒。 -

-

- 致谢:屏幕驱动代码来自微雪 E-Paper Shield,本网页代码最初基于 atc1441/ATC_TLSR_Paper 项目的网页控制端代码修改而来。 -

-
-
+ + + +
- - + + \ No newline at end of file diff --git a/html/js/main.js b/html/js/main.js index 2fe19ba..52f724a 100644 --- a/html/js/main.js +++ b/html/js/main.js @@ -156,7 +156,7 @@ function getImageData(canvas, driver, mode) { } async function sendimg() { - startTime = new Date().getTime(); + const status = document.getElementById("status"); const canvas = document.getElementById("canvas"); const driver = document.getElementById("epddriver").value; const mode = document.getElementById('dithering').value; @@ -164,10 +164,13 @@ async function sendimg() { const ramSize = canvas.width * canvas.height / 8; if (mode === '') { - addLog('请选择一种取模算法!'); + alert('请选择一种取模算法!'); return; } + startTime = new Date().getTime(); + status.parentElement.style.display = "block"; + if (imgArray.length === ramSize * 2) { await epdWrite(driver === "02" ? 0x24 : 0x10, imgArray.slice(0, ramSize)); await epdWrite(driver === "02" ? 0x26 : 0x13, imgArray.slice(ramSize)); @@ -187,6 +190,9 @@ async function sendimg() { const sendTime = (new Date().getTime() - startTime) / 1000.0; addLog(`发送完成!耗时: ${sendTime}s`); setStatus(`发送完成!耗时: ${sendTime}s`); + setTimeout(() => { + status.parentElement.style.display = "none"; + }, 5000); } function updateButtonStatus() { @@ -224,6 +230,10 @@ async function preConnect() { } catch (e) { console.error(e); if (e.message) addLog(e.message); + addLog("请检查蓝牙是否已开启,且使用的浏览器支持蓝牙!建议使用以下浏览器:"); + addLog("• 电脑: Chrome/Edge"); + addLog("• Android: Chrome/Edge"); + addLog("• iOS: Bluefy 浏览器"); return; }