first
This commit is contained in:
commit
6767730181
28
.editorconfig
Normal file
28
.editorconfig
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[{*.c,*.h}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.js]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[{*.html,*.css}]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Build & binary
|
||||||
|
brakeconf
|
||||||
|
dist
|
||||||
|
webui
|
||||||
|
gui/bootstrap*
|
||||||
|
gui/ubuntu-font.css
|
||||||
|
src/html.h
|
2
.prettierignore
Normal file
2
.prettierignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
package-lock.json
|
||||||
|
*.md
|
10
.prettierrc.json
Normal file
10
.prettierrc.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 100,
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"bracketSameLine": true,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"arrowParens": "always",
|
||||||
|
"htmlWhitespaceSensitivity": "strict",
|
||||||
|
"endOfLine": "lf"
|
||||||
|
}
|
1
README.md
Normal file
1
README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
* [Ubuntu](https://assets.ubuntu.com/v1/0cef8205-ubuntu-font-family-0.83.zip) font family.
|
12
build.sh
Executable file
12
build.sh
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
clear
|
||||||
|
|
||||||
|
rm dist/* &> /dev/null
|
||||||
|
rm brakeconf &> /dev/null
|
||||||
|
python3 ./build_gui.py gui/index.html dist/index.html &> /dev/null
|
||||||
|
xxd -i -n html_document dist/index.html > src/html.h
|
||||||
|
# sed -i 's/unsigned char/const unsigned char/g' src/html.h
|
||||||
|
gcc -I./webui -o brakeconf src/device.c src/main.c src/ui.c webui/libwebui-2-static.a -lserialport -ljansson
|
||||||
|
|
||||||
|
./brakeconf icanthink
|
104
build_gui.py
Normal file
104
build_gui.py
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys, re, os
|
||||||
|
from collections import deque
|
||||||
|
from bs4 import BeautifulSoup, Tag
|
||||||
|
from jsmin import jsmin
|
||||||
|
from csscompressor import compress
|
||||||
|
|
||||||
|
# html param
|
||||||
|
html = sys.argv[1]
|
||||||
|
# target param
|
||||||
|
target = sys.argv[2]
|
||||||
|
# path from html param
|
||||||
|
path = re.sub(r"[^\/]*$", "", html)
|
||||||
|
# open html file
|
||||||
|
soup = BeautifulSoup(open(html), 'html.parser')
|
||||||
|
# find last script as anchorpoint
|
||||||
|
lastScript = soup.findAll("script", attrs = {"src" : True})[-1]
|
||||||
|
# get all scripts containing src attribute (= external scripts)
|
||||||
|
scripts = soup.findAll("script", attrs = {"src" : True})
|
||||||
|
# find last style link as anchorpoint
|
||||||
|
lastStylesheet = soup.findAll("link", attrs = {"rel" : "stylesheet"})[-1]
|
||||||
|
# get all links to css stylesheets
|
||||||
|
stylesheets = soup.findAll("link", attrs = {"rel" : "stylesheet"})
|
||||||
|
|
||||||
|
# create list of script srcs
|
||||||
|
print("\nRead Scripts:")
|
||||||
|
scriptsSrc = deque()
|
||||||
|
for script in scripts:
|
||||||
|
scriptsSrc.append(path + script.attrs["src"])
|
||||||
|
print("\t" + path + script.attrs["src"])
|
||||||
|
|
||||||
|
# create list of stylesheets srcs
|
||||||
|
print("\nRead Stylesheets:")
|
||||||
|
stylesheetsSrc = deque()
|
||||||
|
for stylesheet in stylesheets:
|
||||||
|
stylesheetsSrc.append(path + stylesheet.attrs["href"])
|
||||||
|
print("\t" + path + stylesheet.attrs["href"])
|
||||||
|
|
||||||
|
# merge scripts to temp.js
|
||||||
|
print("\nMerge Scripts:")
|
||||||
|
print("\t", end="")
|
||||||
|
with open("temp.js", "w") as outfileScript:
|
||||||
|
for fname in scriptsSrc:
|
||||||
|
# add space every script
|
||||||
|
if fname != 'gui//webui.js':
|
||||||
|
outfileScript.write("\n")
|
||||||
|
print("~", end="")
|
||||||
|
with open(fname) as infile:
|
||||||
|
for line in infile:
|
||||||
|
outfileScript.write(line)
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
# merge stylsheets to temp.css
|
||||||
|
print("Merge Stylesheets:")
|
||||||
|
print("\t", end="")
|
||||||
|
with open("temp.css", "w") as outfileCSS:
|
||||||
|
for fname in stylesheetsSrc:
|
||||||
|
# add space every script
|
||||||
|
outfileCSS.write("\n")
|
||||||
|
print("~", end="")
|
||||||
|
with open(fname) as infile:
|
||||||
|
for line in infile:
|
||||||
|
outfileCSS.write(line)
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
# minify javascript
|
||||||
|
print("Minify temp.js\n\t~")
|
||||||
|
with open("temp.js") as js:
|
||||||
|
minified_js = jsmin(js.read())
|
||||||
|
|
||||||
|
# minify css
|
||||||
|
print("\nMinify temp.css\n\t~")
|
||||||
|
with open("temp.css") as css:
|
||||||
|
minified_css = compress(css.read())
|
||||||
|
|
||||||
|
# replace scripts with merged and min embed script / css
|
||||||
|
print("\nReplacing and deleting\n\t~")
|
||||||
|
tag = soup.new_tag("script")
|
||||||
|
tag["type"] = "text/javascript"
|
||||||
|
tag.append(minified_js)
|
||||||
|
lastScript.replace_with(tag)
|
||||||
|
|
||||||
|
tag = soup.new_tag("style")
|
||||||
|
tag["type"] = "text/css"
|
||||||
|
tag.append(minified_css)
|
||||||
|
lastStylesheet.replace_with(tag)
|
||||||
|
|
||||||
|
#remove script and style tags
|
||||||
|
for script in scripts:
|
||||||
|
script.decompose()
|
||||||
|
for stylesheet in stylesheets:
|
||||||
|
stylesheet.decompose()
|
||||||
|
|
||||||
|
#remove temp
|
||||||
|
os.remove("temp.js")
|
||||||
|
os.remove("temp.css")
|
||||||
|
|
||||||
|
#save html as target
|
||||||
|
file = open(target,"w")
|
||||||
|
file.write(soup.prettify())
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
print("\nFIN\n")
|
177
gui/app.js
Normal file
177
gui/app.js
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const ENABLE_AUTO_CHECK_THEME = false;
|
||||||
|
|
||||||
|
// Перечень кнопок переключения окон
|
||||||
|
const enumWindowButtons = [
|
||||||
|
'btnWindowDevice',
|
||||||
|
'btnWindowTesting',
|
||||||
|
'btnWindowSettings',
|
||||||
|
'btnWindowFirmwareUpdate',
|
||||||
|
'btnWindowLog',
|
||||||
|
'btnWindowAbout',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Перечень окон программы
|
||||||
|
const enumWindow = [
|
||||||
|
'appWindowDevice',
|
||||||
|
'appWindowTesting',
|
||||||
|
'appWindowSettings',
|
||||||
|
'appWindowFirmwareUpdate',
|
||||||
|
'appWindowLog',
|
||||||
|
'appWindowAbout',
|
||||||
|
];
|
||||||
|
|
||||||
|
/* main */
|
||||||
|
window.onload = function () {
|
||||||
|
/* Автоматически активирует тему в зависимости от настроек системы */
|
||||||
|
if (ENABLE_AUTO_CHECK_THEME) {
|
||||||
|
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
|
switch_theme('dark');
|
||||||
|
} else {
|
||||||
|
switch_theme('light');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('btn_theme_switch').addEventListener('click', switch_theme, false);
|
||||||
|
enumWindowButtons.forEach((btn) => {
|
||||||
|
document.getElementById(btn).addEventListener('click', ui_window_btn_active, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('btn_app_close').addEventListener('click', close_app);
|
||||||
|
document.getElementById('btn_port_refresh').addEventListener('click', refresh_ports);
|
||||||
|
document.getElementById('btn_device_connect').addEventListener('click', connect_to_device);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Изменяет тему приложения
|
||||||
|
*/
|
||||||
|
function switch_theme() {
|
||||||
|
let app = document.documentElement;
|
||||||
|
let theme = app.getAttribute('data-bs-theme');
|
||||||
|
|
||||||
|
if (theme == 'auto' || theme == 'light') {
|
||||||
|
app.setAttribute('data-bs-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
app.setAttribute('data-bs-theme', 'light');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
function ui_window_btn_active(clicked_btn) {
|
||||||
|
enumWindowButtons.forEach((btn) => {
|
||||||
|
const button = document.getElementById(btn);
|
||||||
|
button.classList.remove('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
clicked_btn.target.classList.add('active');
|
||||||
|
|
||||||
|
ui_show_window(clicked_btn.target.getAttribute('id').replace('btn', 'app'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
function ui_show_window(window_name) {
|
||||||
|
const current_window = document.getElementById(window_name);
|
||||||
|
|
||||||
|
enumWindow.forEach((w) => {
|
||||||
|
let each_window = document.getElementById(w);
|
||||||
|
each_window.classList.remove('d-flex');
|
||||||
|
each_window.classList.add('d-none');
|
||||||
|
});
|
||||||
|
|
||||||
|
current_window.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обновляет список портов
|
||||||
|
*/
|
||||||
|
function refresh_ports() {
|
||||||
|
const port_selector = document.getElementById('port_selector');
|
||||||
|
|
||||||
|
webui.call('webui_refresh_ports').then((response) => {
|
||||||
|
// const ports_array = JSON.parse(response);
|
||||||
|
const ports_array = response;
|
||||||
|
|
||||||
|
// Проверка длины массива
|
||||||
|
if (ports_array.length > 0) {
|
||||||
|
port_selector.innerHTML = '';
|
||||||
|
} else {
|
||||||
|
alert('Отсутсвуют подключённые устройства!');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ports_array.ports.forEach((port, index) => {
|
||||||
|
if (index == 0) {
|
||||||
|
const default_option = document.createElement('option');
|
||||||
|
default_option.innerText = 'Выберите порт...';
|
||||||
|
default_option.value = 'null';
|
||||||
|
default_option.selected = true;
|
||||||
|
|
||||||
|
port_selector.appendChild(default_option);
|
||||||
|
}
|
||||||
|
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.innerText = port;
|
||||||
|
option.value = port;
|
||||||
|
|
||||||
|
port_selector.appendChild(option);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Подключается к устройству
|
||||||
|
*/
|
||||||
|
function connect_to_device() {
|
||||||
|
const port_selector = document.getElementById('port_selector');
|
||||||
|
const btn_port_refresh = document.getElementById('btn_port_refresh');
|
||||||
|
const btn_device_connect = document.getElementById('btn_device_connect');
|
||||||
|
|
||||||
|
if (port_selector.value == 'null') {
|
||||||
|
alert('Необходимо выбрать порт!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
webui.call('webui_connect_device', port_selector.value);
|
||||||
|
|
||||||
|
if (btn_device_connect.innerText == 'Подключиться') {
|
||||||
|
port_selector.disabled = true;
|
||||||
|
btn_port_refresh.disabled = true;
|
||||||
|
|
||||||
|
btn_device_connect.classList.add('btn-success');
|
||||||
|
btn_device_connect.classList.remove('btn-primary');
|
||||||
|
btn_device_connect.innerText = 'Отключиться';
|
||||||
|
} else {
|
||||||
|
port_selector.disabled = false;
|
||||||
|
btn_port_refresh.disabled = false;
|
||||||
|
|
||||||
|
btn_device_connect.classList.add('btn-primary');
|
||||||
|
btn_device_connect.classList.remove('btn-success');
|
||||||
|
btn_device_connect.innerText = 'Подключиться';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет строку в окно лога
|
||||||
|
*/
|
||||||
|
function add_line_log(text) {
|
||||||
|
const connection_log_console = document.getElementById('connection_log_console');
|
||||||
|
connection_log_console.innerHTML += `${text}\n`;
|
||||||
|
|
||||||
|
/* Автоматически прокручивает лог в конец */
|
||||||
|
const sw_connection_log_autoscroll = document.getElementById('sw_connection_log_autoscroll');
|
||||||
|
if (sw_connection_log_autoscroll.checked) {
|
||||||
|
connection_log_console.scrollTop = connection_log_console.scrollHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function close_app() {
|
||||||
|
webui.call('close_app', 'a').then((response) => {});
|
||||||
|
}
|
319
gui/index.html
Normal file
319
gui/index.html
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="ru" class="h-100" data-bs-theme="light">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Настройка модуля торможения</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="bootstrap-v5.3.1.min.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="ubuntu-font.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="styles.css" />
|
||||||
|
<script src="app.js"></script>
|
||||||
|
<script src="/webui.js"></script>
|
||||||
|
</head>
|
||||||
|
<body class="d-flex h-100 text-bg-dark">
|
||||||
|
<div class="d-flex h-100 mx-auto p-3">
|
||||||
|
<nav class="d-flex flex-column flex-shrink-0 p-3 text-bg-dark" style="width: 300px">
|
||||||
|
<p class="text-center fw-bold m-0"> Настройка модуля<br />торможения </p>
|
||||||
|
<hr />
|
||||||
|
<ul class="nav nav-pills flex-column mb-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a
|
||||||
|
id="btnWindowDevice"
|
||||||
|
class="nav-link text-reset active link-pointer"
|
||||||
|
aria-current="page">
|
||||||
|
<svg
|
||||||
|
class="bi pe-none me-2"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
|
<line x1="22" y1="12" x2="2" y2="12" />
|
||||||
|
<path
|
||||||
|
d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" />
|
||||||
|
<line x1="6" y1="16" x2="6.01" y2="16" />
|
||||||
|
<line x1="10" y1="16" x2="10.01" y2="16" />
|
||||||
|
</svg>
|
||||||
|
Устройство
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a
|
||||||
|
id="btnWindowTesting"
|
||||||
|
class="nav-link text-reset link-pointer"
|
||||||
|
aria-current="page">
|
||||||
|
<svg
|
||||||
|
class="bi pe-none me-2"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
|
<line x1="4" y1="21" x2="4" y2="14" />
|
||||||
|
<line x1="4" y1="10" x2="4" y2="3" />
|
||||||
|
<line x1="12" y1="21" x2="12" y2="12" />
|
||||||
|
<line x1="12" y1="8" x2="12" y2="3" />
|
||||||
|
<line x1="20" y1="21" x2="20" y2="16" />
|
||||||
|
<line x1="20" y1="12" x2="20" y2="3" />
|
||||||
|
<line x1="1" y1="14" x2="7" y2="14" />
|
||||||
|
<line x1="9" y1="8" x2="15" y2="8" />
|
||||||
|
<line x1="17" y1="16" x2="23" y2="16" />
|
||||||
|
</svg>
|
||||||
|
Тестирование
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a
|
||||||
|
id="btnWindowSettings"
|
||||||
|
class="nav-link text-reset link-pointer"
|
||||||
|
aria-current="page">
|
||||||
|
<svg
|
||||||
|
class="bi pe-none me-2"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
|
<path
|
||||||
|
d="M18 3a3 3 0 0 0-3 3v12a3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3H6a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3V6a3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3h12a3 3 0 0 0 3-3 3 3 0 0 0-3-3z" />
|
||||||
|
</svg>
|
||||||
|
Настройка
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a
|
||||||
|
id="btnWindowFirmwareUpdate"
|
||||||
|
class="nav-link text-reset link-pointer"
|
||||||
|
aria-current="page">
|
||||||
|
<svg
|
||||||
|
class="bi pe-none me-2"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
|
<rect x="4" y="4" width="16" height="16" rx="2" ry="2" />
|
||||||
|
<rect x="9" y="9" width="6" height="6" />
|
||||||
|
<line x1="9" y1="1" x2="9" y2="4" />
|
||||||
|
<line x1="15" y1="1" x2="15" y2="4" />
|
||||||
|
<line x1="9" y1="20" x2="9" y2="23" />
|
||||||
|
<line x1="15" y1="20" x2="15" y2="23" />
|
||||||
|
<line x1="20" y1="9" x2="23" y2="9" />
|
||||||
|
<line x1="20" y1="14" x2="23" y2="14" />
|
||||||
|
<line x1="1" y1="9" x2="4" y2="9" />
|
||||||
|
<line x1="1" y1="14" x2="4" y2="14" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
Обновление прошивки
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
id="btnWindowLog"
|
||||||
|
class="nav-link text-reset link-pointer"
|
||||||
|
aria-current="page">
|
||||||
|
<svg
|
||||||
|
class="bi pe-none me-2"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
|
<line x1="21" y1="10" x2="3" y2="10" />
|
||||||
|
<line x1="21" y1="6" x2="3" y2="6" />
|
||||||
|
<line x1="21" y1="14" x2="3" y2="14" />
|
||||||
|
<line x1="21" y1="18" x2="3" y2="18" />
|
||||||
|
</svg>
|
||||||
|
Лог
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a
|
||||||
|
id="btnWindowAbout"
|
||||||
|
class="nav-link text-reset link-pointer"
|
||||||
|
aria-current="page">
|
||||||
|
<svg
|
||||||
|
class="bi pe-none me-2"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="12" r="10" />
|
||||||
|
<line x1="12" y1="8" x2="12" y2="12" />
|
||||||
|
<line x1="12" y1="16" x2="12.01" y2="16" />
|
||||||
|
</svg>
|
||||||
|
О программе
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<hr />
|
||||||
|
<div class="btn-group-vertical btn-group-sm">
|
||||||
|
<button id="btn_theme_switch" class="btn btn-outline-success">
|
||||||
|
Изменить тему
|
||||||
|
</button>
|
||||||
|
<button id="btn_app_close" type="button" class="btn btn-outline-danger">
|
||||||
|
Закрыть
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<p class="text-center m-0">Версия: 1.0.0</p>
|
||||||
|
</nav>
|
||||||
|
<main class="d-flex flex-fill" style="width: 600px">
|
||||||
|
<!-- Device -->
|
||||||
|
<div id="appWindowDevice" class="flex-fill card shadow p-3">
|
||||||
|
<label class="mb-1">Порт для подключения</label>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<select id="port_selector" class="form-select">
|
||||||
|
<option value="null" selected>Выберите порт...</option>
|
||||||
|
</select>
|
||||||
|
<button id="btn_port_refresh" class="btn btn-primary" type="button">
|
||||||
|
Обновить
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="d-grid gap-2 col-6 mx-auto">
|
||||||
|
<button id="btn_device_connect" class="btn btn-primary">
|
||||||
|
Подключиться
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Testing -->
|
||||||
|
<div id="appWindowTesting" class="d-none flex-fill card shadow p-3">
|
||||||
|
<label class="pb-2">Активация режимов</label>
|
||||||
|
<div class="d-flex btn-group mb-3">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="btn-check"
|
||||||
|
id="check_toggle_emergency"
|
||||||
|
autocomplete="off" />
|
||||||
|
<label class="btn btn-outline-danger" for="check_toggle_emergency">
|
||||||
|
АВАРИЙНЫЙ
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="btn-check"
|
||||||
|
id="check_toggle_reverse"
|
||||||
|
autocomplete="off" />
|
||||||
|
<label class="btn btn-outline-success" for="check_toggle_reverse">
|
||||||
|
РЕВЕРС
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- zone switchers -->
|
||||||
|
<label class="pb-2">Переключатели зон</label>
|
||||||
|
<div class="d-flex btn-group mb-3">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
class="btn-check"
|
||||||
|
name="option-zone"
|
||||||
|
id="option_zone_warning"
|
||||||
|
autocomplete="off" />
|
||||||
|
<label class="btn btn-outline-primary" for="option_zone_warning">
|
||||||
|
ПРЕДУПРЕЖДЕНИЕ
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
class="btn-check"
|
||||||
|
name="option-zone"
|
||||||
|
id="option_zone_alert"
|
||||||
|
autocomplete="off" />
|
||||||
|
<label class="btn btn-outline-primary" for="option_zone_alert">
|
||||||
|
ГОТОВНОСТЬ
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
class="btn-check"
|
||||||
|
name="option-zone"
|
||||||
|
id="option_zone_danger"
|
||||||
|
autocomplete="off" />
|
||||||
|
<label class="btn btn-outline-primary" for="option_zone_danger">
|
||||||
|
ОПАСНОСТЬ
|
||||||
|
</label>
|
||||||
|
<button class="btn btn-warning" id="option_zone_reset"> СБРОС </button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- command sender -->
|
||||||
|
<label class="pb-2">Отправить команду</label>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-text">Команда</span>
|
||||||
|
<input id="input_command" type="text" class="form-control" />
|
||||||
|
<button id="btn_send_command" class="btn btn-primary">Отправить</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<div id="appWindowSettings" class="d-none flex-fill card shadow p-3">
|
||||||
|
settings
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- FirmwareUpdate -->
|
||||||
|
<div id="appWindowFirmwareUpdate" class="d-none flex-fill card shadow p-3">
|
||||||
|
FW update
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Log -->
|
||||||
|
<div id="appWindowLog" class="d-none flex-fill card shadow p-3">
|
||||||
|
<div>
|
||||||
|
<textarea
|
||||||
|
id="connection_log_console"
|
||||||
|
class="form-control h-100 font-monospace bg-dark text-bg-dark"
|
||||||
|
rows="15"
|
||||||
|
placeholder="Лог подключения"
|
||||||
|
autocomplete="off"
|
||||||
|
readonly></textarea>
|
||||||
|
<div class="form-check form-switch mt-1">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
role="switch"
|
||||||
|
id="sw_connection_log_autoscroll"
|
||||||
|
checked />
|
||||||
|
<label class="form-check-label" for="sw_connection_log_autoscroll">
|
||||||
|
Автоматическая прокрутка
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<div id="appWindowAbout" class="d-none flex-fill card shadow p-3">
|
||||||
|
<div class="alert alert-info text-center">
|
||||||
|
Программа для настройки
|
||||||
|
<span class="fw-bold">модуля торможения</span>.
|
||||||
|
</div>
|
||||||
|
<div class="alert alert-warning text-center">
|
||||||
|
Разработано специально для
|
||||||
|
<span class="fw-bold">НК-Сервис</span>.
|
||||||
|
</div>
|
||||||
|
<div class="alert alert-dark text-center">2023 by Alexander Popov</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
17
gui/styles.css
Normal file
17
gui/styles.css
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
body {
|
||||||
|
font-family: 'Ubuntu';
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 540px;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
/* color: var(--bs-gray-400) !important;*/
|
||||||
|
font-family: 'Ubuntu Mono';
|
||||||
|
font-size: 0.8rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
14
package.json
Normal file
14
package.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"name": "...",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "...",
|
||||||
|
"author": "Alexander Popov <iiiypuk@fastmail.fm>",
|
||||||
|
"scripts": {
|
||||||
|
"prettier": "npx prettier --write gui",
|
||||||
|
"clean": "rm -rf ./dist/* &> /dev/null"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier": "3.0.1"
|
||||||
|
}
|
||||||
|
}
|
34
src/device.c
Normal file
34
src/device.c
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* AUTHOR: Alexander Popov <iiiypuk {at} fastmail.fm>
|
||||||
|
* DESC: ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
json_t *get_serial_ports() {
|
||||||
|
struct sp_port **port_list;
|
||||||
|
enum sp_return result = sp_list_ports(&port_list);
|
||||||
|
|
||||||
|
json_t *ports_data = NULL;
|
||||||
|
json_t *ports_array = NULL;
|
||||||
|
|
||||||
|
ports_array = json_array();
|
||||||
|
|
||||||
|
if (result == SP_OK) {
|
||||||
|
/* Get the name of the port. */
|
||||||
|
int i;
|
||||||
|
for (i = 0; port_list[i] != NULL; i++) {
|
||||||
|
struct sp_port *port = port_list[i];
|
||||||
|
char *port_name = sp_get_port_name(port);
|
||||||
|
|
||||||
|
json_array_append(ports_array, json_string(port_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
sp_free_port_list(port_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
ports_data = json_object();
|
||||||
|
json_object_set_new(ports_data, "ports", ports_array);
|
||||||
|
|
||||||
|
return ports_data;
|
||||||
|
}
|
14
src/device.h
Normal file
14
src/device.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* AUTHOR: Alexander Popov <iiiypuk {at} fastmail.fm>
|
||||||
|
* DESC: ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEVICE_H_
|
||||||
|
#define DEVICE_H_
|
||||||
|
|
||||||
|
#include <libserialport.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
|
||||||
|
json_t *get_serial_ports();
|
||||||
|
|
||||||
|
#endif
|
30
src/main.c
Normal file
30
src/main.c
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "webui.h"
|
||||||
|
#include "html.h"
|
||||||
|
#include "ui.h"
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
struct sp_port *serial_port;
|
||||||
|
|
||||||
|
int main(int argc, char const *argv[]) {
|
||||||
|
int app_window = webui_new_window();
|
||||||
|
|
||||||
|
html_document[html_document_len] = '\0';
|
||||||
|
|
||||||
|
if (argc > 1 && strcmp(argv[1], "icanthink") == 0) {
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
webui_set_kiosk(app_window, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
webui_bind(app_window, "close_app", close_app);
|
||||||
|
webui_bind(app_window, "webui_refresh_ports", refresh_devices);
|
||||||
|
webui_bind(app_window, "webui_connect_device", connect_device);
|
||||||
|
|
||||||
|
webui_show(app_window, html_document);
|
||||||
|
webui_wait();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
24
src/ui.c
Normal file
24
src/ui.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* AUTHOR: Alexander Popov <iiiypuk {at} fastmail.fm>
|
||||||
|
* DESC: ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ui.h"
|
||||||
|
|
||||||
|
void close_app(webui_event_t* e) {
|
||||||
|
printf("Bye!\n");
|
||||||
|
// webui_destroy();
|
||||||
|
webui_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh_devices(webui_event_t* e) {
|
||||||
|
printf("ololo\n");
|
||||||
|
|
||||||
|
webui_return_string(e, json_dumps(get_serial_ports(), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void connect_device(webui_event_t* e) {
|
||||||
|
const char* str = webui_get_string(e);
|
||||||
|
|
||||||
|
webui_return_bool(e, true);
|
||||||
|
}
|
20
src/ui.h
Normal file
20
src/ui.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* AUTHOR: Alexander Popov <iiiypuk {at} fastmail.fm>
|
||||||
|
* DESC: ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UI_H_
|
||||||
|
#define UI_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <libserialport.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
#include "webui.h"
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
void close_app(webui_event_t* e);
|
||||||
|
void connect_device(webui_event_t* e);
|
||||||
|
void refresh_devices(webui_event_t* e);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user