Compare commits
10 Commits
74aeca7e7d
...
f0a5ba095c
Author | SHA1 | Date | |
---|---|---|---|
f0a5ba095c | |||
aa15fc51ec | |||
e04badb234 | |||
e9b2653ad0 | |||
6598f0e2c3 | |||
6a064a90dc | |||
8da69d19f1 | |||
98cdbc09df | |||
7de9849d9a | |||
46cf67ee91 |
@ -10,7 +10,7 @@ insert_final_newline = true
|
|||||||
|
|
||||||
[{*.c,*.h}]
|
[{*.c,*.h}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 2
|
||||||
|
|
||||||
[*.js]
|
[*.js]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
@ -1 +1,5 @@
|
|||||||
* [Ubuntu](https://assets.ubuntu.com/v1/0cef8205-ubuntu-font-family-0.83.zip) font family.
|
## 🧰 Завиисимости для сборки:
|
||||||
|
|
||||||
|
* webui 2.4.2
|
||||||
|
* Bootstrap 5.3.1
|
||||||
|
* Семейство шрифтов [Ubuntu](https://assets.ubuntu.com/v1/0cef8205-ubuntu-font-family-0.83.zip)
|
||||||
|
14
TODO.md
Normal file
14
TODO.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# 🖱️ Front-end
|
||||||
|
|
||||||
|
* [x] Не работает кнопка сброса переключателей зон (98cdbc09df6d51c58125a17985ada3cd07efbcfb)
|
||||||
|
* [ ] Реализовать проверку пустой команды при нажатии на кнопку `Отправить` команду
|
||||||
|
* [x] Добавить индикаторы аварийного режима и реверса (7de9849d9aa86955d9c8c902177dc54ff802046e)
|
||||||
|
* [ ] Вывод информации об устойстве на вкладке `Устройство`
|
||||||
|
* [ ] Реализовать проверку версии программы из интернета
|
||||||
|
* [ ] Во вкладку `Прошивка` добавить отображение текущей версии прошивки
|
||||||
|
* [ ] Не работает кнопка `Записать параметры` во вкладке `Настройка`
|
||||||
|
* [ ] Не работает кнопка `Прочитать параметры` во вкладке `Настройка`
|
||||||
|
|
||||||
|
# ⚙️ Back-end
|
||||||
|
|
||||||
|
* [ ] Реализовать получение статуса аварийного режима и реверса real-time для UI
|
4
build.sh
4
build.sh
@ -10,11 +10,11 @@ rm brakeconf &> /dev/null
|
|||||||
|
|
||||||
echo "[ 2/$STEPS] Build GUI..."
|
echo "[ 2/$STEPS] Build GUI..."
|
||||||
python3 ./build_gui.py gui/index.html dist/index.html &> /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
|
xxd -i -n app_html dist/index.html > src/html.h
|
||||||
# sed -i 's/unsigned char/const unsigned char/g' src/html.h
|
# sed -i 's/unsigned char/const unsigned char/g' src/html.h
|
||||||
|
|
||||||
echo "[ 3/$STEPS] Compile..."
|
echo "[ 3/$STEPS] Compile..."
|
||||||
gcc -I./webui -o brakeconf src/device.c src/main.c src/ui.c webui/libwebui-2-static.a -lserialport -ljansson
|
gcc -I./webui -o brakeconf src/main.c webui/libwebui-2-static.a -lserialport -ljansson
|
||||||
|
|
||||||
echo "[ 4/$STEPS] Running..."
|
echo "[ 4/$STEPS] Running..."
|
||||||
./brakeconf icanthink
|
./brakeconf icanthink
|
||||||
|
181
build_gui.py
181
build_gui.py
@ -6,99 +6,116 @@ from bs4 import BeautifulSoup, Tag
|
|||||||
from jsmin import jsmin
|
from jsmin import jsmin
|
||||||
from csscompressor import compress
|
from csscompressor import compress
|
||||||
|
|
||||||
# html param
|
IGNORED = 'gui//webui.js'
|
||||||
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
|
if __name__ == '__main__':
|
||||||
print("\nRead Scripts:")
|
# html input param
|
||||||
scriptsSrc = deque()
|
html = sys.argv[1]
|
||||||
for script in scripts:
|
# target output param
|
||||||
scriptsSrc.append(path + script.attrs["src"])
|
target = sys.argv[2]
|
||||||
print("\t" + path + script.attrs["src"])
|
|
||||||
|
|
||||||
# create list of stylesheets srcs
|
# path from html param
|
||||||
print("\nRead Stylesheets:")
|
path = re.sub(r'[^\/]*$', '', html)
|
||||||
stylesheetsSrc = deque()
|
|
||||||
for stylesheet in stylesheets:
|
|
||||||
stylesheetsSrc.append(path + stylesheet.attrs["href"])
|
|
||||||
print("\t" + path + stylesheet.attrs["href"])
|
|
||||||
|
|
||||||
# merge scripts to temp.js
|
# open html file
|
||||||
print("\nMerge Scripts:")
|
print('📂 Open HTML file...', end=' ')
|
||||||
print("\t", end="")
|
soup = BeautifulSoup(open(html), 'html.parser')
|
||||||
with open("temp.js", "w") as outfileScript:
|
print('OK!')
|
||||||
for fname in scriptsSrc:
|
|
||||||
# add space every script
|
# find last script as anchorpoint
|
||||||
if fname != 'gui//webui.js':
|
lastScript = soup.findAll('script', attrs={'src': True})[-1]
|
||||||
outfileScript.write("\n")
|
# get all scripts containing src attribute (= external scripts)
|
||||||
print("~", end="")
|
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('🔎 Create list of scripts...', end=' ')
|
||||||
|
scriptsSrc = deque()
|
||||||
|
for script in scripts:
|
||||||
|
scriptsSrc.append(path + script.attrs['src'])
|
||||||
|
print('Complete!')
|
||||||
|
|
||||||
|
# create list of stylesheets srcs
|
||||||
|
print('🔎 Create list of stylesheets...', end=' ')
|
||||||
|
stylesheetsSrc = deque()
|
||||||
|
for stylesheet in stylesheets:
|
||||||
|
stylesheetsSrc.append(path + stylesheet.attrs['href'])
|
||||||
|
print('Complete!')
|
||||||
|
|
||||||
|
# merge scripts to .temp.js
|
||||||
|
print('📥 Merge scripts...', end=' ')
|
||||||
|
with open('.temp.js', 'w') as outfileScript:
|
||||||
|
for fname in scriptsSrc:
|
||||||
|
# add space every script
|
||||||
|
if fname not in IGNORED:
|
||||||
|
outfileScript.write('\n')
|
||||||
|
with open(fname) as infile:
|
||||||
|
for line in infile:
|
||||||
|
outfileScript.write(line)
|
||||||
|
print('Complete!')
|
||||||
|
|
||||||
|
print('📥 Merge stylsheets...', end=' ')
|
||||||
|
# merge stylsheets to temp.css
|
||||||
|
with open('.temp.css', 'w') as outfileCSS:
|
||||||
|
for fname in stylesheetsSrc:
|
||||||
|
# add space every script
|
||||||
|
outfileCSS.write('\n')
|
||||||
with open(fname) as infile:
|
with open(fname) as infile:
|
||||||
for line in infile:
|
for line in infile:
|
||||||
outfileScript.write(line)
|
outfileCSS.write(line)
|
||||||
print("\n");
|
print('Complete!')
|
||||||
|
|
||||||
# merge stylsheets to temp.css
|
# minify javascript
|
||||||
print("Merge Stylesheets:")
|
print('🗃️ Minify scripts...', end=' ')
|
||||||
print("\t", end="")
|
with open('.temp.js') as js:
|
||||||
with open("temp.css", "w") as outfileCSS:
|
minified_js = jsmin(js.read())
|
||||||
for fname in stylesheetsSrc:
|
print('Complete!')
|
||||||
# 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
|
# minify css
|
||||||
print("Minify temp.js\n\t~")
|
print('🗃️ Minify stylsheets...', end=' ')
|
||||||
with open("temp.js") as js:
|
with open('.temp.css') as css:
|
||||||
minified_js = jsmin(js.read())
|
minified_css = compress(css.read())
|
||||||
|
print('Complete!')
|
||||||
|
|
||||||
# minify css
|
# replace scripts with merged and min embed script / css
|
||||||
print("\nMinify temp.css\n\t~")
|
print('🔄 Embedding script and stylsheets...', end=' ')
|
||||||
with open("temp.css") as css:
|
tag = soup.new_tag('script')
|
||||||
minified_css = compress(css.read())
|
tag['type'] = 'text/javascript'
|
||||||
|
tag.append(minified_js)
|
||||||
|
lastScript.replace_with(tag)
|
||||||
|
|
||||||
# replace scripts with merged and min embed script / css
|
webui_tag = soup.new_tag('script')
|
||||||
print("\nReplacing and deleting\n\t~")
|
webui_tag['type'] = 'text/javascript'
|
||||||
tag = soup.new_tag("script")
|
webui_tag['src'] = '/webui.js'
|
||||||
tag["type"] = "text/javascript"
|
tag.insert_before(webui_tag)
|
||||||
tag.append(minified_js)
|
|
||||||
lastScript.replace_with(tag)
|
|
||||||
|
|
||||||
tag = soup.new_tag("style")
|
tag = soup.new_tag('style')
|
||||||
tag["type"] = "text/css"
|
tag['type'] = 'text/css'
|
||||||
tag.append(minified_css)
|
tag.append(minified_css)
|
||||||
lastStylesheet.replace_with(tag)
|
lastStylesheet.replace_with(tag)
|
||||||
|
print('Complete!')
|
||||||
|
|
||||||
#remove script and style tags
|
# remove script and style tags
|
||||||
for script in scripts:
|
print('🧹 Cleaning...', end=' ')
|
||||||
script.decompose()
|
for script in scripts:
|
||||||
for stylesheet in stylesheets:
|
script.decompose()
|
||||||
stylesheet.decompose()
|
for stylesheet in stylesheets:
|
||||||
|
stylesheet.decompose()
|
||||||
|
|
||||||
#remove temp
|
# remove temp files
|
||||||
os.remove("temp.js")
|
os.remove('.temp.js')
|
||||||
os.remove("temp.css")
|
os.remove('.temp.css')
|
||||||
|
print('Complete!')
|
||||||
|
|
||||||
#save html as target
|
# save html as target
|
||||||
file = open(target,"w")
|
print('💾 Save builded document...', end=' ')
|
||||||
file.write(soup.prettify())
|
file = open(target, 'w')
|
||||||
file.close()
|
file.write(soup.prettify())
|
||||||
|
file.close()
|
||||||
|
print('Complete!', end='\n\n')
|
||||||
|
|
||||||
print("\nFIN\n")
|
print('🏁 Complete')
|
||||||
|
37
gui/app.js
37
gui/app.js
@ -41,6 +41,8 @@ window.onload = function () {
|
|||||||
document.getElementById('btn_app_close').addEventListener('click', close_app);
|
document.getElementById('btn_app_close').addEventListener('click', close_app);
|
||||||
document.getElementById('btn_port_refresh').addEventListener('click', refresh_ports);
|
document.getElementById('btn_port_refresh').addEventListener('click', refresh_ports);
|
||||||
document.getElementById('btn_device_connect').addEventListener('click', connect_to_device);
|
document.getElementById('btn_device_connect').addEventListener('click', connect_to_device);
|
||||||
|
|
||||||
|
document.getElementById('option_zone_reset').addEventListener('click', reset_test_zones);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -125,7 +127,7 @@ function refresh_ports() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Подключается к устройству
|
* Подключается к выбранному устройству
|
||||||
*/
|
*/
|
||||||
function connect_to_device() {
|
function connect_to_device() {
|
||||||
const port_selector = document.getElementById('port_selector');
|
const port_selector = document.getElementById('port_selector');
|
||||||
@ -137,7 +139,9 @@ function connect_to_device() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
webui.call('webui_connect_device', port_selector.value);
|
webui.call('webui_connect_device', port_selector.value).then((response) => {
|
||||||
|
alert(`!: ${response}`);
|
||||||
|
});
|
||||||
|
|
||||||
if (btn_device_connect.innerText == 'Подключиться') {
|
if (btn_device_connect.innerText == 'Подключиться') {
|
||||||
port_selector.disabled = true;
|
port_selector.disabled = true;
|
||||||
@ -170,6 +174,35 @@ function add_line_log(text) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Меняет состояние checkbox'а статуса режимов в окне `Тестирование`
|
||||||
|
*/
|
||||||
|
function set_mode_status(mode, status) {
|
||||||
|
const set_value = (element, status) => (element.checked = status);
|
||||||
|
|
||||||
|
if (mode == 'emergency') {
|
||||||
|
const element = document.getElementById('mode_status_emergency');
|
||||||
|
status ? set_value(element, status) : set_value(element, status);
|
||||||
|
} else if (mode == 'reverse') {
|
||||||
|
const element = document.getElementById('mode_status_reverse');
|
||||||
|
status ? set_value(element, status) : set_value(element, status);
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Сбрасывает состояние переключателей зон в окне `Тестирование`
|
||||||
|
*/
|
||||||
|
function reset_test_zones() {
|
||||||
|
const option_zones = document.getElementsByName('option-zone');
|
||||||
|
for (let checkbox of option_zones) {
|
||||||
|
checkbox.checked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
120
gui/index.html
120
gui/index.html
@ -7,8 +7,8 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="bootstrap-v5.3.1.min.css" />
|
<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="ubuntu-font.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css" />
|
<link rel="stylesheet" type="text/css" href="styles.css" />
|
||||||
<script src="app.js"></script>
|
|
||||||
<script src="/webui.js"></script>
|
<script src="/webui.js"></script>
|
||||||
|
<script src="/app.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="d-flex h-100 text-bg-dark">
|
<body class="d-flex h-100 text-bg-dark">
|
||||||
<div class="d-flex h-100 mx-auto p-3">
|
<div class="d-flex h-100 mx-auto p-3">
|
||||||
@ -181,7 +181,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<p class="text-center m-0">Версия: 1.0.0</p>
|
<p class="text-center m-0">Версия: 0.9.9</p>
|
||||||
</nav>
|
</nav>
|
||||||
<main class="d-flex flex-fill" style="width: 600px">
|
<main class="d-flex flex-fill" style="width: 600px">
|
||||||
<!-- Device -->
|
<!-- Device -->
|
||||||
@ -205,6 +205,44 @@
|
|||||||
|
|
||||||
<!-- Testing -->
|
<!-- Testing -->
|
||||||
<div id="appWindowTesting" class="d-none flex-fill card shadow p-3">
|
<div id="appWindowTesting" class="d-none flex-fill card shadow p-3">
|
||||||
|
<!-- Статус режимов -->
|
||||||
|
<!--
|
||||||
|
Отображает в реальном времени состоянии активации
|
||||||
|
аварийного режима и реверса
|
||||||
|
-->
|
||||||
|
<p class="text-center">Статус режимов</p>
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-text rounded-bottom-0">
|
||||||
|
<input
|
||||||
|
id="mode_status_emergency"
|
||||||
|
class="form-check-input mt-0"
|
||||||
|
type="checkbox"
|
||||||
|
onclick="return false;" />
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="form-control rounded-bottom-0"
|
||||||
|
value="Аварийный режим"
|
||||||
|
readonly />
|
||||||
|
</div>
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-text border-top-0 rounded-top-0">
|
||||||
|
<input
|
||||||
|
id="mode_status_reverse"
|
||||||
|
class="form-check-input mt-0"
|
||||||
|
type="checkbox"
|
||||||
|
onclick="return false;" />
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="form-control border-top-0 rounded-top-0"
|
||||||
|
value="Реверс"
|
||||||
|
readonly />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Активация аварийного режима и реверса -->
|
||||||
<p class="text-center">Активация режимов</p>
|
<p class="text-center">Активация режимов</p>
|
||||||
<div class="d-flex btn-group mb-3">
|
<div class="d-flex btn-group mb-3">
|
||||||
<input
|
<input
|
||||||
@ -267,9 +305,77 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Settings -->
|
<!-- Окно `Настройка` -->
|
||||||
<div id="appWindowSettings" class="d-none flex-fill card shadow p-3">
|
<div id="appWindowSettings" class="d-none flex-fill card shadow p-3">
|
||||||
<div class="alert alert-danger text-center">В разработке</div>
|
<div class="form-check form-switch">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
id="setting_buzzer"
|
||||||
|
checked />
|
||||||
|
<label class="form-check-label" for="setting_buzzer">Включить зуммер</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
id="setting_zones_by_analog"
|
||||||
|
checked />
|
||||||
|
<label class="form-check-label" for="setting_zones_by_analog">
|
||||||
|
Активация зоны аналоговым методом
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<p class="text-center">Настройка времени работы штока актуатора</p>
|
||||||
|
<div class="row mb-1">
|
||||||
|
<label for="setting_rod_full_push" class="col-6 col-form-label">
|
||||||
|
Полное освобождение педали
|
||||||
|
</label>
|
||||||
|
<div class="col-6">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="form-control"
|
||||||
|
id="setting_rod_full_push"
|
||||||
|
min="200"
|
||||||
|
max="4000" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1">
|
||||||
|
<label for="setting_rod_pre_brake" class="col-6 col-form-label">
|
||||||
|
Предварительное торможение
|
||||||
|
</label>
|
||||||
|
<div class="col-6">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="form-control"
|
||||||
|
id="setting_rod_pre_brake"
|
||||||
|
min="200"
|
||||||
|
max="4000" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1">
|
||||||
|
<label for="setting_rod_full_brake" class="col-6 col-form-label">
|
||||||
|
Полное торможение
|
||||||
|
</label>
|
||||||
|
<div class="col-6">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="form-control"
|
||||||
|
id="setting_rod_full_brake"
|
||||||
|
min="200"
|
||||||
|
max="4000" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<button class="btn btn-primary">Записать параметры</button>
|
||||||
|
<button class="btn btn-outline-success">Прочитать параметры</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- FirmwareUpdate -->
|
<!-- FirmwareUpdate -->
|
||||||
@ -304,13 +410,11 @@
|
|||||||
<p class="text-center">О программе</p>
|
<p class="text-center">О программе</p>
|
||||||
<div class="alert alert-info text-center">
|
<div class="alert alert-info text-center">
|
||||||
Программа для настройки
|
Программа для настройки
|
||||||
<span class="fw-bold">модуля торможения</span>
|
<span class="fw-bold">модуля торможения</span>.
|
||||||
</div>
|
<br />
|
||||||
<div class="alert alert-warning text-center">
|
|
||||||
Разработано специально для
|
Разработано специально для
|
||||||
<span class="fw-bold">НК-Сервис</span>
|
<span class="fw-bold">НК-Сервис</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="alert alert-dark text-center">2023 by Alexander Popov</div>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
4
pyproject.toml
Normal file
4
pyproject.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[tool.black]
|
||||||
|
skip-string-normalization = true
|
||||||
|
pycodestyle = true
|
||||||
|
line-length = 100
|
@ -8,4 +8,7 @@
|
|||||||
|
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
|
|
||||||
|
#include "html.h"
|
||||||
|
struct sp_port *serial_port;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
34
src/device.c
34
src/device.c
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
70
src/device.h
70
src/device.h
@ -6,9 +6,73 @@
|
|||||||
#ifndef DEVICE_H_
|
#ifndef DEVICE_H_
|
||||||
#define DEVICE_H_
|
#define DEVICE_H_
|
||||||
|
|
||||||
#include <libserialport.h>
|
int check(enum sp_return result) {
|
||||||
#include <jansson.h>
|
char *error_message;
|
||||||
|
|
||||||
json_t *get_serial_ports();
|
switch (result) {
|
||||||
|
case SP_ERR_ARG:
|
||||||
|
puts("Error: Invalid argument.");
|
||||||
|
abort();
|
||||||
|
case SP_ERR_FAIL:
|
||||||
|
error_message = sp_last_error_message();
|
||||||
|
printf("Error: Failed: %s\n", error_message);
|
||||||
|
sp_free_error_message(error_message);
|
||||||
|
abort();
|
||||||
|
case SP_ERR_SUPP:
|
||||||
|
puts("Error: Not supported.");
|
||||||
|
abort();
|
||||||
|
case SP_ERR_MEM:
|
||||||
|
puts("Error: Couldn't allocate memory.");
|
||||||
|
abort();
|
||||||
|
case SP_OK:
|
||||||
|
default:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
json_t *device_get_available() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_connect(const char *port_name) {
|
||||||
|
check(sp_get_port_by_name(port_name, &serial_port));
|
||||||
|
check(sp_open(serial_port, SP_MODE_READ_WRITE));
|
||||||
|
|
||||||
|
check(sp_set_baudrate(serial_port, 9600));
|
||||||
|
check(sp_set_bits(serial_port, 8));
|
||||||
|
check(sp_set_parity(serial_port, SP_PARITY_NONE));
|
||||||
|
check(sp_set_stopbits(serial_port, 1));
|
||||||
|
check(sp_set_flowcontrol(serial_port, SP_FLOWCONTROL_NONE));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_disconnect() {
|
||||||
|
sp_close(serial_port);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
29
src/main.c
29
src/main.c
@ -1,32 +1,31 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <libserialport.h>
|
||||||
|
#include <jansson.h>
|
||||||
#include "webui.h"
|
#include "webui.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "html.h"
|
|
||||||
#include "ui.h"
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "ui.h"
|
||||||
struct sp_port *serial_port;
|
|
||||||
|
|
||||||
int main(int argc, char const *argv[]) {
|
int main(int argc, char const *argv[]) {
|
||||||
int app_window = webui_new_window();
|
int app_window = webui_new_window();
|
||||||
|
|
||||||
html_document[html_document_len] = '\0';
|
app_html[app_html_len] = '\0';
|
||||||
|
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
webui_set_kiosk(app_window, true);
|
webui_set_kiosk(app_window, true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
webui_bind(app_window, "close_app", close_app);
|
webui_bind(app_window, "close_app", app_close);
|
||||||
webui_bind(app_window, "webui_refresh_ports", refresh_devices);
|
webui_bind(app_window, "webui_refresh_ports", app_refresh_devices);
|
||||||
webui_bind(app_window, "webui_connect_device", connect_device);
|
webui_bind(app_window, "webui_connect_device", app_connect_device);
|
||||||
|
|
||||||
printf("Enjoy :)\n");
|
printf("Enjoy :)\n");
|
||||||
|
|
||||||
webui_show(app_window, html_document);
|
webui_show(app_window, app_html);
|
||||||
webui_wait();
|
webui_wait();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
28
src/ui.c
28
src/ui.c
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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) {
|
|
||||||
const char *available_ports = json_dumps(get_serial_ports(), 0);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("Доступные порты:\n%s\n", available_ports);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
webui_return_string(e, available_ports);
|
|
||||||
}
|
|
||||||
|
|
||||||
void connect_device(webui_event_t* e) {
|
|
||||||
const char* str = webui_get_string(e);
|
|
||||||
|
|
||||||
webui_return_bool(e, true);
|
|
||||||
}
|
|
35
src/ui.h
35
src/ui.h
@ -6,16 +6,33 @@
|
|||||||
#ifndef UI_H_
|
#ifndef UI_H_
|
||||||
#define UI_H_
|
#define UI_H_
|
||||||
|
|
||||||
#include <stdio.h>
|
void app_close(webui_event_t* e) {
|
||||||
#include <libserialport.h>
|
printf("Bye!\n");
|
||||||
#include <jansson.h>
|
webui_exit();
|
||||||
#include "webui.h"
|
}
|
||||||
|
|
||||||
#include "config.h"
|
void app_refresh_devices(webui_event_t* e) {
|
||||||
#include "device.h"
|
const char *available_ports = json_dumps(device_get_available(), 0);
|
||||||
|
|
||||||
void close_app(webui_event_t* e);
|
#ifdef DEBUG
|
||||||
void connect_device(webui_event_t* e);
|
printf("Доступные порты:\n%s\n", available_ports);
|
||||||
void refresh_devices(webui_event_t* e);
|
#endif
|
||||||
|
|
||||||
|
webui_return_string(e, available_ports);
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_connect_device(webui_event_t* e) {
|
||||||
|
const char* port = webui_get_string(e);
|
||||||
|
int result;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Подключение к порту: %s\n", port);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO: Необходимо проверить подключение
|
||||||
|
result = device_connect(port);
|
||||||
|
|
||||||
|
webui_return_bool(e, (bool)result);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user