Compare commits

...

24 Commits

Author SHA1 Message Date
Ondřej Hruška f729d91651
minor updates in about.php 6 years ago
Ondřej Hruška ae38110816
added a help section about GPIO API, update DE translations 6 years ago
Ondřej Hruška 2e014f4312
add a form for configuring GPIOs 2, 4, 5 6 years ago
Ondřej Hruška ef05565155
upgrade node packages so build works again, compat w node 10 6 years ago
cpsdqs 86abce86aa
Update German translation 6 years ago
Ondřej Hruška e25523de11
Merge hungarian translations from master to work 7 years ago
Ondřej Hruška 1a05b70b6c
fix some js escaping issues 7 years ago
schneemaier c55ceb1298 Added missing Hungarian translations (#2) 7 years ago
Ondřej Hruška 8b43b1d171
Merge branch 'work' 7 years ago
Ondřej Hruška 36f0f60dbd
added some missing czech translations 7 years ago
Ondřej Hruška a0412c0e9e
Merge branch 'work' 7 years ago
Ondřej Hruška fed47ffda9
update help 7 years ago
Ondřej Hruška 68a467c33e
Merge branch 'double-lines' into work 7 years ago
cpsdqs 681685fa3b
Stop using weird transforms for double-width 7 years ago
cpsdqs 915113a628
Fix incorrect rendering of double-sized lines 7 years ago
Ondřej Hruška 0893b0a268
added update topic for doublelines 7 years ago
Ondřej Hruška d489e99194
fixed double height always being also double width 7 years ago
cpsdqs f61d861883
Make cursor work in double-width lines 7 years ago
cpsdqs 4e9970300b
Add layout support for double size lines 7 years ago
cpsdqs 45766fccce
Add renderer support for double-size lines 7 years ago
cpsdqs 244ee72531
Improve fancy graphics performance 7 years ago
cpsdqs f7f5658685
Make touch & mouse tracking work 7 years ago
cpsdqs f590741d97
Update demo for new protocol 7 years ago
Ondřej Hruška 9cab25ed4d
add info about new OSC to help 7 years ago
  1. 4
      _debug_replacements.php
  2. 5
      js/term/debug.js
  3. 8
      js/term/demo.js
  4. 39
      js/term/screen.js
  5. 5
      js/term/screen_layout.js
  6. 30
      js/term/screen_parser.js
  7. 145
      js/term/screen_renderer.js
  8. 15
      lang/cs.php
  9. 28
      lang/de.php
  10. 10
      lang/en.php
  11. 28
      lang/hu.php
  12. 4
      package.json
  13. 4
      pages/about.php
  14. 40
      pages/cfg_system.php
  15. 1
      pages/help.php
  16. 102
      pages/help/cmd_screen.php
  17. 137
      pages/help/cmd_system.php
  18. 39
      pages/help/iocontrol.php
  19. 1925
      yarn.lock

@ -87,6 +87,10 @@ return [
'sta_mac' => '5c:cf:7f:02:74:51',
'ap_mac' => '5e:cf:7f:02:74:51',
'gpio2_conf' => '0',
'gpio4_conf' => '1',
'gpio5_conf' => '1',
'width' => '80',
'height' => '25',

@ -203,6 +203,11 @@ module.exports = function attachDebugger (screen, connection) {
ctx.fillStyle = '#0ff'
}
if (flags & 16) {
// was filled to speed up rendering
ctx.globalAlpha /= 2
}
ctx.fillRect(x * cellSize.width, y * cellSize.height, cellSize.width, cellSize.height)
if (flags & 8) {

@ -276,10 +276,8 @@ class ScrollingTerminal {
data += encodeAsCodePoint(25)
data += encodeAsCodePoint(80)
data += encodeAsCodePoint(this.theme)
data += encodeAsCodePoint(this.defaultFG & 0xFFFF)
data += encodeAsCodePoint(this.defaultFG >> 16)
data += encodeAsCodePoint(this.defaultBG & 0xFFFF)
data += encodeAsCodePoint(this.defaultBG >> 16)
data += this.encodeColor(this.defaultFG)
data += this.encodeColor(this.defaultBG)
let attributes = +this.cursor.visible
attributes |= (3 << 5) * +this.trackMouse // track mouse controls both
attributes |= 3 << 7 // buttons/links always visible
@ -290,7 +288,7 @@ class ScrollingTerminal {
getButtons () {
let data = 'B'
data += encodeAsCodePoint(this.buttonLabels.length)
data += this.buttonLabels.map(x => x + '\x01').join('')
data += this.buttonLabels.map(x => `\x01${x}\x01`).join('')
return data
}
getTitle () {

@ -90,6 +90,14 @@ module.exports = class TermScreen extends EventEmitter {
this.screenFG = []
this.screenBG = []
this.screenAttrs = []
this.screenLines = []
// For testing TODO remove
// this.screenLines[0] = 0b001
// this.screenLines[1] = 0b010
// this.screenLines[2] = 0b100
// this.screenLines[3] = 0b011
// this.screenLines[4] = 0b101
let selecting = false
@ -149,6 +157,11 @@ module.exports = class TermScreen extends EventEmitter {
touchPosition = getTouchPositionOffset(e.touches[0])
touchDidMove = false
touchDownTime = Date.now()
if (this.mouseMode.clicks) {
this.emit('mousedown', ...this.layout.screenToGrid(...touchPosition), 1)
e.preventDefault()
}
})
this.layout.on('touchmove', e => {
@ -161,6 +174,9 @@ module.exports = class TermScreen extends EventEmitter {
} else if (selecting) {
e.preventDefault()
selectMove(...touchPosition)
} else if (this.mouseMode.movement && !selecting) {
this.emit('mousemove', ...this.layout.screenToGrid(...touchPosition))
e.preventDefault()
}
touchDidMove = true
@ -183,6 +199,9 @@ module.exports = class TermScreen extends EventEmitter {
)
this.emit('show-touch-select-menu', selectionPos[0], selectionPos[1])
} else if (this.mouseMode.clicks) {
this.emit('mouseup', ...this.layout.screenToGrid(...touchPosition), 1)
e.preventDefault()
}
if (!touchDidMove && !this.mouseMode.clicks) {
@ -190,7 +209,7 @@ module.exports = class TermScreen extends EventEmitter {
x: touchPosition[0],
y: touchPosition[1]
}))
}
} else if (!touchDidMove) this.resetSelection()
touchPosition = null
})
@ -199,10 +218,7 @@ module.exports = class TermScreen extends EventEmitter {
if (this.selection.start[0] !== this.selection.end[0] ||
this.selection.start[1] !== this.selection.end[1]) {
// selection is not empty
// reset selection
this.selection.start = this.selection.end = [0, 0]
this.emit('hide-touch-select-menu')
this.renderScreen('select-reset')
this.resetSelection()
} else {
e.preventDefault()
this.emit('open-soft-keyboard')
@ -258,6 +274,7 @@ module.exports = class TermScreen extends EventEmitter {
this.screen.screenFG = new Array(width * height).fill(0)
this.screen.screenBG = new Array(width * height).fill(0)
this.screen.screenAttrs = new Array(width * height).fill(0)
this.screen.screenLines = new Array(height).fill(0)
}
updateLayout () {
@ -280,6 +297,7 @@ module.exports = class TermScreen extends EventEmitter {
screenBG: this.screenBG,
screenSelection: selection,
screenAttrs: this.screenAttrs,
screenLines: this.screenLines,
cursor: this.cursor,
statusScreen: this.window.statusScreen,
reverseVideo: this.reverseVideo,
@ -287,6 +305,12 @@ module.exports = class TermScreen extends EventEmitter {
})
}
resetSelection () {
this.selection.start = this.selection.end = [0, 0]
this.emit('hide-touch-select-menu')
this.renderScreen('select-reset')
}
/**
* Returns a normalized version of the current selection, such that `start`
* is always before `end`.
@ -476,6 +500,11 @@ module.exports = class TermScreen extends EventEmitter {
this.emit('opts-update')
break
case 'double-lines':
this.screenLines = update.lines
this.renderScreen('double-lines')
break
case 'static-opts':
this.layout.window.fontFamily = update.fontStack || null
this.layout.window.fontSize = update.fontSize

@ -135,8 +135,9 @@ module.exports = class ScreenLayout extends EventEmitter {
x = x / this._windowScale - this._padding
y = y / this._windowScale - this._padding
x = Math.floor((x + (rounded ? cellSize.width / 2 : 0)) / cellSize.width)
y = Math.floor(y / cellSize.height)
if (this.renderer.drawnScreenLines[y]) x /= 2 // double size
x = Math.floor((x + (rounded ? cellSize.width / 2 : 0)) / cellSize.width)
x = Math.max(0, Math.min(this.window.width - 1, x))
y = Math.max(0, Math.min(this.window.height - 1, y))
@ -153,6 +154,8 @@ module.exports = class ScreenLayout extends EventEmitter {
gridToScreen (x, y, withScale = false) {
let cellSize = this.getCellSize()
if (this.renderer.drawnScreenLines[y]) x *= 2 // double size
return [x * cellSize.width, y * cellSize.height].map(v => this._padding + (withScale ? v * this._windowScale : v))
}

@ -27,15 +27,17 @@ function du (str) {
}
/* eslint-disable no-multi-spaces */
const TOPIC_SCREEN_OPTS = 'O'
const TOPIC_STATIC_OPTS = 'P'
const TOPIC_CONTENT = 'S'
const TOPIC_TITLE = 'T'
const TOPIC_BUTTONS = 'B'
const TOPIC_CURSOR = 'C'
const TOPIC_INTERNAL = 'D'
const TOPIC_BELL = '!'
const TOPIC_BACKDROP = 'W'
// mnemonic
const TOPIC_SCREEN_OPTS = 'O' // O-ptions
const TOPIC_STATIC_OPTS = 'P' // P-arams
const TOPIC_CONTENT = 'S' // S-creen
const TOPIC_TITLE = 'T' // T-itle
const TOPIC_BUTTONS = 'B' // B-uttons
const TOPIC_CURSOR = 'C' // C-ursor
const TOPIC_INTERNAL = 'D' // D-ebug
const TOPIC_BELL = '!' // !!!
const TOPIC_BACKDROP = 'W' // W-allpaper
const TOPIC_DOUBLE_LINES = 'H' // H-uge
const OPT_CURSOR_VISIBLE = (1 << 0)
const OPT_DEBUGBAR = (1 << 1)
@ -188,6 +190,16 @@ module.exports = class ScreenParser {
fontSize
})
} else if (topic === TOPIC_DOUBLE_LINES) {
let lines = []
const count = du(strArray[ci++])
for (let i = 0; i < count; i++) {
// format: INDEX<<3 | (dbl-h-bot : dbl-h-top : dbl-w)
let n = du(strArray[ci++])
lines[n >> 3] = n & 0b111
}
updates.push({ topic: 'double-lines', lines: lines })
} else if (topic === TOPIC_TITLE) {
updates.push({ topic: 'title', title: collectOneTerminatedString() })

@ -60,6 +60,7 @@ module.exports = class CanvasRenderer extends EventEmitter {
this.screenBG = []
this.screenAttrs = []
this.screenSelection = []
this.screenLines = []
this.cursor = {}
this.reverseVideo = false
this.hasBlinkingCells = false
@ -96,6 +97,7 @@ module.exports = class CanvasRenderer extends EventEmitter {
this.drawnScreenFG = []
this.drawnScreenBG = []
this.drawnScreenAttrs = []
this.drawnScreenLines = []
this.drawnCursor = [-1, -1, '', false]
}
@ -209,6 +211,9 @@ module.exports = class CanvasRenderer extends EventEmitter {
drawBackground ({ x, y, cellWidth, cellHeight, bg, isDefaultBG }) {
const { ctx, width, height, padding } = this
// is a double-width/double-height line
if (this.screenLines[y] & 0b001) cellWidth *= 2
ctx.fillStyle = this.getColor(bg)
let screenX = x * cellWidth + padding
let screenY = y * cellHeight + padding
@ -276,6 +281,39 @@ module.exports = class CanvasRenderer extends EventEmitter {
let screenX = x * cellWidth + padding
let screenY = y * cellHeight + padding
const dblWidth = this.screenLines[y] & 0b001
const dblHeightTop = this.screenLines[y] & 0b010
const dblHeightBot = this.screenLines[y] & 0b100
if (this.screenLines[y]) {
// is a double-width/double-height line
if (dblWidth) cellWidth *= 2
ctx.save()
ctx.translate(padding, screenY + 0.5 * cellHeight)
if (dblWidth) ctx.scale(2, 1)
if (dblHeightTop) {
// top half
ctx.scale(1, 2)
ctx.translate(0, cellHeight / 4)
} else if (dblHeightBot) {
// bottom half
ctx.scale(1, 2)
ctx.translate(0, -cellHeight / 4)
}
ctx.translate(-padding, -screenY - 0.5 * cellHeight)
if (dblWidth) ctx.translate(-cellWidth / 4, 0)
if (dblHeightBot || dblHeightTop) {
// characters overflow -- needs clipping
// TODO: clipping is really expensive
ctx.beginPath()
if (dblHeightTop) ctx.rect(screenX, screenY, cellWidth, cellHeight / 2)
else ctx.rect(screenX, screenY + cellHeight / 2, cellWidth, cellHeight / 2)
ctx.clip()
}
}
let codePoint = text.codePointAt(0)
if (codePoint >= 0x2580 && codePoint <= 0x259F) {
// block elements
@ -450,6 +488,8 @@ module.exports = class CanvasRenderer extends EventEmitter {
ctx.stroke()
}
if (this.screenLines[y]) ctx.restore()
ctx.globalAlpha = 1
}
@ -558,6 +598,7 @@ module.exports = class CanvasRenderer extends EventEmitter {
fg !== this.drawnScreenFG[cell] || // foreground updated, and this cell has text
bg !== this.drawnScreenBG[cell] || // background updated
attrs !== this.drawnScreenAttrs[cell] || // attributes updated
this.screenLines[y] !== this.drawnScreenLines[y] || // line updated
// TODO: fix artifacts or keep this hack:
isCursor || wasCursor || // cursor blink/position updated
(isCursor && this.cursor.style !== this.drawnCursor[2]) || // cursor style updated
@ -570,6 +611,28 @@ module.exports = class CanvasRenderer extends EventEmitter {
updateMap.set(cell, didUpdate)
}
// set drawn screen lines
this.drawnScreenLines = this.screenLines.slice()
let debugFilledUpdates = []
if (this.graphics >= 1) {
// fancy graphics gets really slow when there's a lot of masks
// so here's an algorithm that fills in holes in the update map
for (let cell of updateMap.keys()) {
if (updateMap.get(cell)) continue
let previous = updateMap.get(cell - 1) || false
let next = updateMap.get(cell + 1) || false
if (previous && next) {
// set cell to true of horizontally adjacent updated
updateMap.set(cell, true)
if (this.debug && this._debug) debugFilledUpdates.push(cell)
}
}
}
// Map of (cell index) -> boolean, whether or not a cell should be redrawn
const redrawMap = new Map()
const maskedCells = new Map()
@ -594,7 +657,10 @@ module.exports = class CanvasRenderer extends EventEmitter {
// update this cell if:
// - the adjacent cell updated (For now, this'll always be true because characters can be slightly larger than they say they are)
// - the adjacent cell updated and this cell or the adjacent cell is wide
if (updateMap.get(adjacentCell) && (this.graphics < 2 || isWideCell || isTextWide(this.screen[adjacentCell]))) {
// - this or the adjacent cell is not double-sized
if (updateMap.get(adjacentCell) &&
(this.graphics < 2 || isWideCell || isTextWide(this.screen[adjacentCell])) &&
(!this.screenLines[Math.floor(cell / this.width)] && !this.screenLines[Math.floor(adjacentCell / this.width)])) {
adjacentDidUpdate = true
if (this.getAdjacentCells(cell, 1).includes(adjacentCell)) {
@ -621,11 +687,54 @@ module.exports = class CanvasRenderer extends EventEmitter {
// TODO: include padding in border cells
const padding = this.padding
let clipRegion = (regionStart, y, endX) => {
let regions = []
for (let y = 0; y < height; y++) {
let regionStart = null
for (let x = 0; x < width; x++) {
let cell = y * width + x
let masked = maskedCells.get(cell)
if (masked && regionStart === null) regionStart = x
if (!masked && regionStart !== null) {
regions.push([regionStart, y, x, y + 1])
regionStart = null
}
}
if (regionStart !== null) {
regions.push([regionStart, y, width, y + 1])
}
}
// join regions if possible (O(n^2-1), sorry)
let i = 0
while (i < regions.length) {
let region = regions[i]
let j = 0
while (j < regions.length) {
let other = regions[j]
if (other === region) {
j++
continue
}
if (other[0] === region[0] && other[2] === region[2] && other[3] === region[1]) {
region[1] = other[1]
regions.splice(j, 1)
if (i > j) i--
j--
}
j++
}
i++
}
ctx.save()
ctx.beginPath()
for (let region of regions) {
let [regionStart, y, endX, endY] = region
let rectX = padding + regionStart * cellWidth
let rectY = padding + y * cellHeight
let rectWidth = (endX - regionStart) * cellWidth
let rectHeight = cellHeight
let rectHeight = (endY - y) * cellHeight
// compensate for padding
if (regionStart === 0) {
@ -641,24 +750,6 @@ module.exports = class CanvasRenderer extends EventEmitter {
ctx.rect(rectX, rectY, rectWidth, rectHeight)
}
ctx.save()
ctx.beginPath()
for (let y = 0; y < height; y++) {
let regionStart = null
for (let x = 0; x < width; x++) {
let cell = y * width + x
let masked = maskedCells.get(cell)
if (masked && regionStart === null) regionStart = x
if (!masked && regionStart !== null) {
clipRegion(regionStart, y, x)
regionStart = null
}
}
if (regionStart !== null) {
clipRegion(regionStart, y, width)
}
}
ctx.clip()
}
@ -676,6 +767,7 @@ module.exports = class CanvasRenderer extends EventEmitter {
flags |= (+updateMap.get(cell)) << 1
flags |= (+maskedCells.get(cell)) << 2
flags |= (+isTextWide(text)) << 3
flags |= (+debugFilledUpdates.includes(cell)) << 4
this._debug.setCell(cell, flags)
}
}
@ -716,17 +808,22 @@ module.exports = class CanvasRenderer extends EventEmitter {
let cursorX = x
let cursorY = y
let cursorWidth = cellWidth // JS doesn't allow same-name assignment
if (this.cursor.hanging) {
// draw hanging cursor in the margin
cursorX += 1
}
let screenX = cursorX * cellWidth + this.padding
// double-width lines
if (this.screenLines[cursorY] & 0b001) cursorWidth *= 2
let screenX = cursorX * cursorWidth + this.padding
let screenY = cursorY * cellHeight + this.padding
if (this.cursor.style === 'block') {
// block
ctx.rect(screenX, screenY, cellWidth, cellHeight)
ctx.rect(screenX, screenY, cursorWidth, cellHeight)
} else if (this.cursor.style === 'bar') {
// vertical bar
let barWidth = 2
@ -734,7 +831,7 @@ module.exports = class CanvasRenderer extends EventEmitter {
} else if (this.cursor.style === 'line') {
// underline
let lineHeight = 2
ctx.rect(screenX, screenY + charSize.height, cellWidth, lineHeight)
ctx.rect(screenX, screenY + charSize.height, cursorWidth, lineHeight)
}
ctx.clip()

@ -235,6 +235,11 @@ return [
'persist.restore_hard_explain' =>
'(Tímto vymažete nastavení WiFi! Záloha a systémové heslo zůstanou beze změny.)',
'backup.title' => 'Záloha do souboru',
'backup.explain' => 'Všechna nastavení kromě systémového hesla je možné uložit do a obnovit z INI souboru.',
'backup.export' => 'Zálohovat do souboru',
'backup.import' => 'Nahrát soubor!',
// UART settings form
'uart.title' => 'Sériový port',
@ -260,6 +265,16 @@ return [
obrazovky a stránky se budou načítat rychleji. Nevýhodou je vyšší spotřeba a citlivost k~rušení.
',
'hwtuning.overclock' => 'Přetaktovat na 160~MHz',
'gpio2_config' => 'Funkce GPIO2',
'gpio4_config' => 'Funkce GPIO4',
'gpio5_config' => 'Funkce GPIO5',
'gpio_config.off' => 'Vypnuto',
'gpio_config.off_2' => 'Debug UART Tx',
'gpio_config.out_initial0' => 'Výstup (výchozí stav 0)',
'gpio_config.out_initial1' => 'Výstup (výchozí stav 1)',
'gpio_config.in_pull' => 'Vstup (s pull-upem)',
'gpio_config.in_nopull' => 'Vstup (plovoucí)',
// Generic button / dialog labels

@ -80,6 +80,10 @@ return [
'term.debugbar' => 'Debug-Leiste anzeigen',
'term.ascii_debug' => 'Kontrollcodes anzeigen',
'term.backdrop' => 'Hintergrundbild-URL',
'term.button_count' => 'Tastenanzahl',
'term.button_colors' => 'Tastenfarben',
'term.font_stack' => 'Schriftstapel',
'term.font_size' => 'Schriftgröße',
'cursor.block_blink' => 'Block, blinkend',
'cursor.block_steady' => 'Block, ruhig',
@ -180,7 +184,7 @@ return [
'pwlock.title' => 'Zugriffsbeschränkungen',
'pwlock.explain' => '
Manche, oder alle Teile des Web-Interface können mit einem Passwort geschützt werden.
Lass die Passwortfelder leer wenn du es sie verändern möchtest.<br>
Lass die Passwortfelder leer wenn du es nicht verändern möchtest.<br>
Das voreingestellte Passwort ist "%def_access_pw%".',
'pwlock.region' => 'Geschützte Seiten',
'pwlock.region.none' => 'Keine, alles offen',
@ -229,6 +233,11 @@ return [
(Dies löscht die WLAN-Konfiguration! Beeinflusst die gespeicherten Voreinstellungen
oder das Systempasswort nicht.)',
'backup.title' => 'Konfigurationsdatei sichern',
'backup.explain' => 'Die ganze Konfiguration außer dem Systempasswort können mit einer INI-Datei gesichert und wiederhergestellt werden.',
'backup.export' => 'Datei exportieren',
'backup.import' => 'Importieren!',
// UART settings form
'uart.title' => 'Serieller Port Parameter',
@ -250,11 +259,22 @@ return [
'hwtuning.title' => 'Hardware-Tuning',
'hwtuning.explain' => '
ESP8266 kann übertaktet werden von 80&nbsp;MHz auf 160&nbsp;MHz.
Der ESP8266 kann von 80&nbsp;MHz auf 160&nbsp;MHz übertaktet werden.
Alles wird etwas schneller sein, aber mit höherem Stromverbrauch,
und eventuell auch mit höherer Interferenz. Mit Sorgfalt benutzen.
und eventuell auch mit mehr Interferenz.
Mit Sorgfalt benutzen.
',
'hwtuning.overclock' => 'Übertakten',
'hwtuning.overclock' => 'Auf 160MHz übertakten',
'gpio2_config' => 'GPIO2 Funktion',
'gpio4_config' => 'GPIO4 Funktion',
'gpio5_config' => 'GPIO5 Funktion',
'gpio_config.off' => 'Deaktiviert',
'gpio_config.off_2' => 'UART Tx Debuggen',
'gpio_config.out_initial0' => 'Output (Anfangslevel 0)',
'gpio_config.out_initial1' => 'Output (Anfangslevel 1)',
'gpio_config.in_pull' => 'Input (pull-up)',
'gpio_config.in_nopull' => 'Input (floating)',
// Generic button / dialog labels

@ -266,6 +266,16 @@ return [
',
'hwtuning.overclock' => 'Overclock to 160MHz',
'gpio2_config' => 'GPIO2 function',
'gpio4_config' => 'GPIO4 function',
'gpio5_config' => 'GPIO5 function',
'gpio_config.off' => 'Disabled',
'gpio_config.off_2' => 'Debug UART Tx',
'gpio_config.out_initial0' => 'Output (initial 0)',
'gpio_config.out_initial1' => 'Output (initial 1)',
'gpio_config.in_pull' => 'Input (pull-up)',
'gpio_config.in_nopull' => 'Input (floating)',
// Generic button / dialog labels
'apply' => 'Apply!',

@ -23,7 +23,7 @@ return [
'term_nav.paste' => 'Beillesztés',
'term_nav.upload' => 'Feltöltés',
'term_nav.keybd' => 'Billentyűzet',
'term_nav.paste_prompt' => 'Szöveg beillesztése és küldés:',
'term_nav.paste_prompt' => 'Szöveg beillesztése és küldése:',
'term_conn.connecting' => 'Csatlakozás',
'term_conn.waiting_content' => 'Várakozás a csatlakozásra',
@ -80,6 +80,10 @@ return [
'term.debugbar' => 'Belső állapot hibakeresés',
'term.ascii_debug' => 'Kontroll kódok mutatása',
'term.backdrop' => 'Háttérkép URL.je',
'term.button_count' => 'Gomb szám',
'term.button_colors' => 'Gomb színek',
'term.font_stack' => 'Betű típus',
'term.font_size' => 'Betű méret',
'cursor.block_blink' => 'Blokk, villog',
'cursor.block_steady' => 'Blokk, fix',
@ -229,6 +233,12 @@ return [
'persist.restore_hard_explain' =>
'(Ez törli a Wifi beállításokat, de nincs hatása az admin jelszóra.)',
'backup.title' => 'Configurációs fájl biztonsági másolat készítés',
'backup.explain' => 'Minden beállítás menthető és visszaállítható az admin jelszó kivételévelAll config except the admin password can be backed up and restored using egy .INI fájllal.',
'backup.export' => 'Fáljbe exportálás',
'backup.import' => 'Importálás!',
// UART settings form
'uart.title' => 'Soros port paraméterek',
@ -241,7 +251,7 @@ return [
'uart.parity.none' => 'Egyiksem',
'uart.parity.odd' => 'Páratlan',
'uart.parity.even' => 'Páros',
'uart.stop_bits' => 'Stop-bite',
'uart.stop_bits' => 'Stop-bit',
'uart.stop_bits.one' => 'Egy',
'uart.stop_bits.one_and_half' => 'Másfél',
'uart.stop_bits.two' => 'Kettő',
@ -257,13 +267,23 @@ return [
',
'hwtuning.overclock' => 'Órajel emelése 160MHz-re',
'gpio2_config' => 'GPIO2 function', // TODO translate
'gpio4_config' => 'GPIO4 function',
'gpio5_config' => 'GPIO5 function',
'gpio_config.off' => 'Disabled',
'gpio_config.off_2' => 'Debug UART Tx',
'gpio_config.out_initial0' => 'Output (initial 0)',
'gpio_config.out_initial1' => 'Output (initial 1)',
'gpio_config.in_pull' => 'Input (pull-up)',
'gpio_config.in_nopull' => 'Input (floating)',
// Generic button / dialog labels
'apply' => 'Alkalmaz',
'start' => 'Start',
'cancel' => 'Mégse',
'enabled' => 'Engedélyez',
'disabled' => 'Letilt',
'enabled' => 'Engedélyezve',
'disabled' => 'Letiltva',
'yes' => 'Igen',
'no' => 'Nem',
'confirm' => 'OK',

@ -8,10 +8,10 @@
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.0",
"babel-preset-minify": "^0.2.0",
"html-minifier": "^3.5.5",
"node-sass": "^4.5.3",
"standard": "^10.0.3",
"webpack": "^3.6.0",
"html-minifier": "^3.5.5"
"webpack": "^3.6.0"
},
"scripts": {
"webpack": "webpack --display-modules $@",

@ -10,8 +10,8 @@
</p>
<p>
<a href="http://measure.feld.cvut.cz/" target="blank">Katedra měření, FEL ČVUT</a><br>
Department of Measurement, FEE CTU
Vyvinuto na <a href="http://measure.feld.cvut.cz/" target="blank">Katedře měření, FEL ČVUT</a><br>
Developed at the Department of Measurement, FEE CTU in Prague
</p>
</div>

@ -8,7 +8,7 @@
<div class="Row buttons2">
<a class="button icn-restore"
onclick="return confirm('<?= tr('persist.confirm_restore') ?>');"
onclick="return confirm('<?= e(tr('persist.confirm_restore')) ?>');"
href="<?= e(url('restore_defaults')) ?>">
<?= tr('persist.restore_defaults') ?>
</a>
@ -19,7 +19,7 @@
</div>
<div class="Row buttons2">
<a onclick="return confirm('<?= tr('persist.confirm_restore_hard') ?>');"
<a onclick="return confirm('<?= e(tr('persist.confirm_restore_hard')) ?>');"
href="<?= e(url('restore_hard')) ?>">
<?= tr('persist.restore_hard') ?>
</a><br>
@ -63,6 +63,39 @@
--><span class="box" tabindex=0 role=checkbox></span>
<input type="hidden" id="overclock" name="overclock" value="%overclock%">
</div>
<div class="Row">
<label for="gpio2_conf"><?= tr("gpio2_config") ?></label>
<select name="gpio2_conf" id="gpio2_conf">
<option value="0"><?= tr("gpio_config.off_2") ?></option>
<option value="1"><?= tr("gpio_config.out_initial0") ?></option>
<option value="2"><?= tr("gpio_config.out_initial1") ?></option>
<option value="3"><?= tr("gpio_config.in_pull") ?></option>
<option value="4"><?= tr("gpio_config.in_nopull") ?></option>
</select>
</div>
<div class="Row">
<label for="gpio4_conf"><?= tr("gpio4_config") ?></label>
<select name="gpio4_conf" id="gpio4_conf">
<option value="0"><?= tr("gpio_config.off") ?></option>
<option value="1"><?= tr("gpio_config.out_initial0") ?></option>
<option value="2"><?= tr("gpio_config.out_initial1") ?></option>
<option value="3"><?= tr("gpio_config.in_pull") ?></option>
<option value="4"><?= tr("gpio_config.in_nopull") ?></option>
</select>
</div>
<div class="Row">
<label for="gpio5_conf"><?= tr("gpio5_config") ?></label>
<select name="gpio5_conf" id="gpio5_conf">
<option value="0"><?= tr("gpio_config.off") ?></option>
<option value="1"><?= tr("gpio_config.out_initial0") ?></option>
<option value="2"><?= tr("gpio_config.out_initial1") ?></option>
<option value="3"><?= tr("gpio_config.in_pull") ?></option>
<option value="4"><?= tr("gpio_config.in_nopull") ?></option>
</select>
</div>
<div class="Row buttons">
<a class="button icn-ok" href="#" onclick="qs('#form-hw').submit()"><?= tr('apply') ?></a>
@ -154,4 +187,7 @@ $NOFILL = 'readonly onfocus="this.removeAttribute(\'readonly\')" style="cursor:t
}
$('#pwlock').val(%pwlock%);
$('#gpio2_conf').val(%gpio2_conf%);
$('#gpio4_conf').val(%gpio4_conf%);
$('#gpio5_conf').val(%gpio5_conf%);
</script>

@ -18,6 +18,7 @@
<?php require __DIR__ . "/help/cmd_screen.php"; ?>
<?php require __DIR__ . "/help/cmd_d2d.php"; ?>
<?php require __DIR__ . "/help/cmd_system.php"; ?>
<?php require __DIR__ . "/help/iocontrol.php"; ?>
<script>
function hpfold(yes) {

@ -8,60 +8,124 @@
If an argument is left out, it's treated as 0 or 1, depending on what makes sense for the command.
</p>
<h3>Erasing &amp; Inserting</h3>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td>`\e[<i>m</i>J`</td>
<td>
`\e[<i>m</i>J`
Clear part of screen. _m_: 0 - from cursor, 1 - to cursor, 2 - all
</td>
</tr>
<tr>
<td>`\e[<i>m</i>K`</td>
<td>
Clear part of screen. _m_: 0 - from cursor, 1 - to cursor, 2 - all
Erase part of line. _m_: 0 - from cursor, 1 - to cursor, 2 - all
</td>
</tr>
<tr>
<td>`\e[<i>n</i>X`</td>
<td>
`\e[<i>m</i>K`
Erase _n_ characters in line.
</td>
</tr>
<tr>
<td><code>
\e[<i>n</i>L \\
\e[<i>n</i>M
</code></td>
<td>
Erase part of line. _m_: 0 - from cursor, 1 - to cursor, 2 - all
Insert (`L`) or delete (`M`) _n_ lines. Following lines are pulled up or pushed down.
</td>
</tr>
<tr>
<td><code>
\e[<i>n</i>@ \\
\e[<i>n</i>P
</code></td>
<td>
`\e[<i>n</i>X`</td>
Insert (`@`) or delete (`P`) _n_ characters. The rest of the line is pulled left or pushed right.
Characters going past the end of line are lost.
</td>
</tr>
</tbody>
</table>
<h3>Supersized lines</h3>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td>`\e#1`, `\e#2`</td>
<td>
Erase _n_ characters in line.
Make the current line part of a double-height line.
Use `1` for the top, `2` for the bottom half.
</td>
</tr>
<tr>
<td>`\e#3`, `\e#4`</td>
<td>
`\e[<i>n</i>b`</td>
Make the current line part of a double-width, double-height line.
Use `3` for the top, `4` for the bottom half.
</td>
</tr>
<tr>
<td>`\e#6`</td>
<td>
Repeat last printed characters _n_ times (moving cursor and using the current style).
Make the current line double-width.
</td>
</tr>
<tr>
<td>`\e#5`</td>
<td>
<code>
\e[<i>n</i>L \\
\e[<i>n</i>M
</code>
Reset the current line to normal size.
</td>
</tr>
</tbody>
</table>
<h3>Other</h3>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td>`\ec`</td>
<td>
Insert (`L`) or delete (`M`) _n_ lines. Following lines are pulled up or pushed down.
Clear screen, reset attributes and cursor. This command also restores the default
screen size, title, button labels and messages and the background URL.
</td>
</tr>
<tr>
<td><code>
\e[?1049h \\
\e[?1049l
</code></td>
<td>
<code>
\e[<i>n</i>@ \\
\e[<i>n</i>P
</code>
Switch to (`h`) or from (`l`) an alternate screen.
ESPTerm can't implement this fully, so the original screen content is not saved,
but it will remember the cursor, screen size, terminal title, button labels and messages.
</td>
</tr>
<tr>
<td>`\e[8;<i>r</i>;<i>c</i>t`</td>
<td>Set screen size to _r_ rows and _c_ columns (this is a command borrowed from Xterm)</td>
</tr>
<tr>
<td>
Insert (`@`) or delete (`P`) _n_ characters. The rest of the line is pulled left or pushed right.
Characters going past the end of line are lost.
`\e[<i>n</i>b`</td>
<td>
Repeat last printed characters _n_ times (moving cursor and using the current style).
</td>
</tr>
<tr>
<td>`\e#8`</td>
<td>
Reset all screen attributes to default and fill the screen with the letter "E". This was
historically used for aligning CRT displays, now can be useful e.g. for testing erasing commands.
</td>
</tr>
</tbody>

@ -8,6 +8,8 @@
Those changes are not retained after restart.
</p>
<h3>Single-byte commands &amp; queries</h3>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
@ -28,17 +30,6 @@
This message contains the curretn version, unique ID, and the IP address if in Client mode.
</td>
</tr>
<tr>
<td>`\ec`</td>
<td>
Clear screen, reset attributes and cursor. This command also restores the default
screen size, title, button labels and messages and the background URL.
</td>
</tr>
<tr>
<td>`\e[8;<i>r</i>;<i>c</i>t`</td>
<td>Set screen size to _r_ rows and _c_ columns (this is a command borrowed from Xterm)</td>
</tr>
<tr>
<td>`\e[5n`</td>
<td>
@ -46,6 +37,14 @@
Can be used to check if the terminal has booted up and is ready to receive commands.
</td>
</tr>
</tbody>
</table>
<h3>Setting parameters</h3>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td>`\e[<i>n</i> q`</td>
<td>
@ -77,22 +76,18 @@
</td>
</tr>
<tr>
<td>
<code>
\e]28;<i>x</i>;<i>t</i>\a
</code>
</td>
<td><code>
\e]28;<i>x</i>;<i>t</i>\a
</code></td>
<td>
Set label for button _x_ (1-5) to _t_ - e.g.`\e]28;1;Yes\a`
sets the first button text to "Yes".
</td>
</tr>
<tr>
<td>
<code>
\e]29;<i>x</i>;<i>m</i>\a
</code>
</td>
<td><code>
\e]29;<i>x</i>;<i>m</i>\a
</code></td>
<td>
Set message for button _x_ (1-5) to _m_ - e.g.`\e]29;3;+\a`
sets the 3rd button to send "+" when pressed. The message can be up to
@ -100,58 +95,39 @@
</td>
</tr>
<tr>
<td><code>
\e]30;<i>x</i>;<i>c</i>\a
</code></td>
<td>
<code>
\e]9;<i>t</i>\a
</code>
</td>
<td>
Show a notification with text _t_. This will be either a desktop notification
or a pop-up balloon.
Set button _x_ (1-5) color to _c_ - e.g.`\e]30;2;#00FF00\a`
makes the 2nd button green. Supported are SGR colors 1-255
and TrueColor in the format `#RRGGBB`. Use 0 to
reset to the default color.
</td>
</tr>
<tr>
<td>
<code>
\e[?<i>n</i>s \\
\e[?<i>n</i>r
</code>
</td>
<td>
Save (`s`) and restore (`r`) any option set using `CSI ? <i>n</i> h`.
This is used by some applications to back up the original state before
making changes.
</td>
</tr>
<tr>
<td>
<code>
\e[?800h \\
\e[?800l
</code>
</td>
<td><code>
\e[?800h \\
\e[?800l
</code></td>
<td>
Show (`h`) or hide (`l`) the action buttons (the blue buttons under the screen).
</td>
</tr>
<tr>
<td>
<code>
\e[?801h \\
\e[?801l
</code>
</td>
<td><code>
\e[?801h \\
\e[?801l
</code></td>
<td>
Show (`h`) or hide (`l`) menu/help links under the screen.
</td>
</tr>
<tr>
<td>
<code>
\e[?2004h \\
\e[?2004l
</code>
</td>
<td><code>
\e[?2004h \\
\e[?2004l
</code></td>
<td>
Enable (`h`) or disable (`l`) Bracketed Paste mode.
This mode makes any text sent using the Upload Tool be preceded by `\e[200\~`
@ -160,28 +136,41 @@
</td>
</tr>
<tr>
<td><code>
\e[12h \\
\e[12l
</code></td>
<td>
<code>
\e[?1049h \\
\e[?1049l
</code>
</td>
<td>
Switch to (`h`) or from (`l`) an alternate screen.
ESPTerm can't implement this fully, so the original screen content is not saved,
but it will remember the cursor, screen size, terminal title, button labels and messages.
Enable (`h`) or disable (`l`) Send-Receive Mode (SRM).
SRM is the opposite of Local Echo, meaning `\e[12h` disables and `\e[12l` enables Local Echo.
</td>
</tr>
</tbody>
</table>
<h3>Other</h3>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td><code>
\e]9;<i>t</i>\a
</code></td>
<td>
<code>
\e[12h \\
\e[12l
</code>
Show a notification with text _t_. This will be either a desktop notification
or a pop-up balloon.
</td>
</tr>
<tr>
<td><code>
\e[?<i>n</i>s \\
\e[?<i>n</i>r
</code></td>
<td>
Enable (`h`) or disable (`l`) Send-Receive Mode (SRM).
SRM is the opposite of Local Echo, meaning `\e[12h` disables and `\e[12l` enables Local Echo.
Save (`s`) and restore (`r`) any option set using `CSI ? <i>n</i> h`.
This is used by some applications to back up the original state before
making changes.
</td>
</tr>
</tbody>

@ -0,0 +1,39 @@
<div class="Box fold">
<h2>Remote GPIO Control</h2>
<div class="Row v">
<p>
ESPTerm provides a simple API to remotely control and read GPIO pins GPIO2, GPIO4, and GPIO5.
The main use of this API is to remotely reset a device that communicates with ESPTerm
through the UART.
</p>
<p>
GPIO2 is normally used for debug UART, so when used as GPIO, debug logging is disabled. You
can configure the pin functions in <a href="<?= url('cfg_system') ?>">System Settings</a>.
</p>
<p>
The GPIO control endpoint is `/api/v1/gpio`, with optional GET arguments:
</p>
<ul>
<li>`do2=<i>x</i>` - set GPIO2 level. <i>x</i> can be `0`, `1`, or `t` to toggle the pin.
<li>`do4=<i>x</i>` - set GPIO4 level
<li>`do5=<i>x</i>` - set GPIO5 level
<li>`pulse=<i>ms</i>` - the command starts a pulse. After the given amount of time
(milliseconds) has elapsed, the pins are set to the opposite levels than what was specified
(in the case of toggle, the original pin state)
</ul>
<p>
A quick example: <a href="/api/v1/gpio?do4=1&amp;pulse=500">`/api/v1/gpio?do4=1&amp;pulse=500`</a>
sends a 500ms long positive pulse on GPIO4.
</p>
<p>
The GPIO endpoint always returns a JSON object like this: `{"io2":0,"io4":1,"io5":0}`, showing
the current input levels. Input reading works always, regardless of the GPIO settings.
</p>
</div>
</div>

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save